Module: Familia::Utils

Included in:
Familia
Defined in:
lib/familia/utils.rb

Overview

Family-related utility methods

Instance Method Summary collapse

Instance Method Details

#dbkey(*val) ⇒ String

Creates a dbkey from given values

Parameters:

  • val (Array)

    elements to join for the key

Returns:



26
27
28
# File 'lib/familia/utils.rb', line 26

def dbkey(*val)
  join(*val)
end

#distinguisher(value_to_distinguish, strict_values: true) ⇒ String?

This method determines the appropriate transformation to apply based on the class of the input argument.

The method uses a case statement to handle different classes: - For Symbol, String, Integer, and Float classes, it traces the operation and converts the value to a string. - For Familia::Horreum class, it traces the operation and returns the identifier of the value. - For TrueClass, FalseClass, and NilClass, it traces the operation and converts the value to a string (“true”, “false”, or “”). - For any other class, it traces the operation and returns nil.

Alternative names for value_to_distinguish could be input_value, value, or object.

Parameters:

  • value_to_distinguish (Object)

    The value to be processed. Keep in mind that all data is stored as a string so whatever the type of the value, it will be converted to a string.

  • strict_values (Boolean) (defaults to: true)

    Whether to enforce strict value handling. Defaults to true.

Returns:

  • (String, nil)

    The processed value as a string or nil for unsupported classes.



96
97
98
99
100
101
102
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/familia/utils.rb', line 96

def distinguisher(value_to_distinguish, strict_values: true)
  case value_to_distinguish
  when ::Symbol, ::String, ::Integer, ::Float
    Familia.trace :TOREDIS_DISTINGUISHER, dbclient, 'string', caller(1..1) if Familia.debug?

    # Symbols and numerics are naturally serializable to strings
    # so it's a relatively low risk operation.
    value_to_distinguish.to_s

  when ::TrueClass, ::FalseClass, ::NilClass
    Familia.trace :TOREDIS_DISTINGUISHER, dbclient, 'true/false/nil', caller(1..1) if Familia.debug?

    # TrueClass, FalseClass, and NilClass are considered high risk because their
    # original types cannot be reliably determined from their serialized string
    # representations. This can lead to unexpected behavior during deserialization.
    # For instance, a TrueClass value serialized as "true" might be deserialized as
    # a String, causing application errors. Even more problematic, a NilClass value
    # serialized as an empty string makes it impossible to distinguish between a
    # nil value and an empty string upon deserialization. Such scenarios can result
    # in subtle, hard-to-diagnose bugs. To mitigate these risks, we raise an
    # exception when encountering these types unless the strict_values option is
    # explicitly set to false.
    #
    raise Familia::HighRiskFactor, value_to_distinguish if strict_values

    value_to_distinguish.to_s #=> "true", "false", ""

  when Familia::Base, Class
    Familia.trace :TOREDIS_DISTINGUISHER, dbclient, 'base', caller(1..1) if Familia.debug?

    # When called with a class we simply transform it to its name. For
    # instances of Familia class, we store the identifier.
    if value_to_distinguish.is_a?(Class)
      value_to_distinguish.name
    else
      value_to_distinguish.identifier
    end

  else
    Familia.trace :TOREDIS_DISTINGUISHER, dbclient, "else1 #{strict_values}", caller(1..1) if Familia.debug?

    if value_to_distinguish.class.ancestors.member?(Familia::Base)
      Familia.trace :TOREDIS_DISTINGUISHER, dbclient, 'isabase', caller(1..1) if Familia.debug?

      value_to_distinguish.identifier

    else
      Familia.trace :TOREDIS_DISTINGUISHER, dbclient, "else2 #{strict_values}", caller(1..1) if Familia.debug?
      raise Familia::HighRiskFactor, value_to_distinguish if strict_values

      nil
    end
  end
end

#join(*val) ⇒ String

Joins array elements with Familia delimiter

Parameters:

  • val (Array)

    elements to join

Returns:



12
13
14
# File 'lib/familia/utils.rb', line 12

def join(*val)
  val.compact.join(Familia.delim)
end

#now(name = Time.now) ⇒ Float

Returns current time in UTC as a float

Parameters:

  • name (Time) (defaults to: Time.now)

    time object (default: current time)

Returns:

  • (Float)

    time in seconds since epoch



41
42
43
# File 'lib/familia/utils.rb', line 41

def now(name = Time.now)
  name.utc.to_f
end

#pretty_path(filepath) ⇒ Pathname, ...

Converts an absolute file path to a path relative to the current working directory. This simplifies logging and error reporting by showing only the relevant parts of file paths instead of lengthy absolute paths.

Examples:

Using current directory as base

Utils.pretty_path("/home/dev/project/lib/config.rb") # => "lib/config.rb"

Path outside current directory

Utils.pretty_path("/etc/hosts") # => "hosts"

Nil input

Utils.pretty_path(nil) # => nil

Parameters:

  • filepath (String, Pathname)

    The file path to convert

Returns:

  • (Pathname, String, nil)

    A relative path from current directory, basename if path goes outside current directory, or nil if filepath is nil

See Also:

  • Ruby standard library documentation


169
170
171
172
173
174
175
176
177
178
179
# File 'lib/familia/utils.rb', line 169

def pretty_path(filepath)
  return nil if filepath.nil?

  basepath = Dir.pwd
  relative_path = Pathname.new(filepath).relative_path_from(basepath)
  if relative_path.to_s.start_with?('..')
    File.basename(filepath)
  else
    relative_path
  end
end

#pretty_stack(skip: 1, limit: 5) ⇒ String

Formats a stack trace with pretty file paths for improved readability

Examples:

Utils.pretty_stack(limit: 10)
# => "lib/models/user.rb:25:in `save'\n lib/controllers/app.rb:45:in `create'"

Parameters:

  • limit (Integer) (defaults to: 5)

    Maximum number of stack frames to include (default: 3)

Returns:

  • (String)

    Formatted stack trace with relative paths joined by newlines



189
190
191
# File 'lib/familia/utils.rb', line 189

def pretty_stack(skip: 1, limit: 5)
  caller(skip..(skip + limit + 1)).first(limit).map { |frame| pretty_path(frame) }.join("\n")
end

#qstamp(quantum = 10.minutes, pattern: nil, time: nil) ⇒ Integer, String

A quantized timestamp

Examples:

Familia.qstamp  # Returns an integer timestamp rounded to the nearest 10 minutes
Familia.qstamp(1.hour)  # Uses 1 hour quantum
Familia.qstamp(10.minutes, pattern: '%H:%M')  # Returns a formatted string like "12:30"
Familia.qstamp(10.minutes, time: 1302468980)  # Quantizes the given Unix timestamp
Familia.qstamp(10.minutes, time: Time.now)  # Quantizes the given Time object
Familia.qstamp(10.minutes, pattern: '%H:%M', time: 1302468980)  # Formats a specific time

Parameters:

  • quantum (Integer) (defaults to: 10.minutes)

    The time quantum in seconds (default: 10 minutes).

  • pattern (String, nil) (defaults to: nil)

    The strftime pattern to format the timestamp.

  • time (Integer, Float, Time, nil) (defaults to: nil)

    A specific time to quantize (default: current time).

Returns:

  • (Integer, String)

    A unix timestamp or formatted timestamp string.



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/familia/utils.rb', line 60

def qstamp(quantum = 10.minutes, pattern: nil, time: nil)
  time ||= Familia.now
  time = time.to_f if time.is_a?(Time)

  rounded = time - (time % quantum)

  if pattern
    Time.at(rounded).utc.strftime(pattern)
  else
    Time.at(rounded).utc.to_i
  end
end

#serverid(uri) ⇒ Object

Gets server ID without DB component for pool identification



31
32
33
34
35
36
# File 'lib/familia/utils.rb', line 31

def serverid(uri)
  # Create a copy of URI without DB for server identification
  uri = uri.dup
  uri.db = nil
  uri.serverid
end

#split(val) ⇒ Array

Splits a string using Familia delimiter

Parameters:

  • val (String)

    string to split

Returns:

  • (Array)

    split elements



19
20
21
# File 'lib/familia/utils.rb', line 19

def split(val)
  val.split(Familia.delim)
end