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:

  • (String)

    dbkey



76
77
78
# File 'lib/familia/utils.rb', line 76

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

#join(*val) ⇒ String

Joins array elements with Familia delimiter

Parameters:

  • val (Array)

    elements to join

Returns:

  • (String)

    joined string



62
63
64
# File 'lib/familia/utils.rb', line 62

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

#now(current_time = Time.now) ⇒ Float

Returns current time in UTC as a float

Parameters:

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

    time object (default: current time)

Returns:

  • (Float)

    time in seconds since epoch



91
92
93
# File 'lib/familia/utils.rb', line 91

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

#now_in_μsInteger Also known as: now_in_microseconds

Returns the current time in microseconds. This is used to measure the duration of Database commands.

Alias: now_in_microseconds

Returns:

  • (Integer)

    The current time in microseconds.



101
102
103
# File 'lib/familia/utils.rb', line 101

def now_in_μs
  Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
end

#positive?(ret) ⇒ Boolean, Redis::Future

Future-aware positive check for Redis command return values.

For commands where 0 means "nothing happened" and positive means "something happened" (e.g., EXISTS, DEL, LINSERT, TTL checks).

Examples:

Check if key exists

ret = dbclient.exists(key)
Familia.positive?(ret)  #=> true if key exists

Check TTL inside pipeline

pipelined do
  ret = dbclient.ttl(key)
  Familia.positive?(ret)  #=> Redis::Future (passthrough)
end

Parameters:

  • ret (Integer, Redis::Future)

    The return value from a Redis command

Returns:

  • (Boolean, Redis::Future)

    true/false for concrete values, passthrough for Futures



55
56
57
# File 'lib/familia/utils.rb', line 55

def positive?(ret)
  ret.is_a?(Redis::Future) ? ret : ret.positive?
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


151
152
153
154
155
156
157
158
159
160
161
# File 'lib/familia/utils.rb', line 151

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



171
172
173
# File 'lib/familia/utils.rb', line 171

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: Familia.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.



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/familia/utils.rb', line 120

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



81
82
83
84
85
86
# File 'lib/familia/utils.rb', line 81

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



69
70
71
# File 'lib/familia/utils.rb', line 69

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

#success?(ret) ⇒ Boolean, Redis::Future

Future-aware success check for Redis command return values.

Redis commands like HSET return 0 (updated existing) or 1 (created new). Both are success states. Inside a pipeline or transaction, the return value is a Redis::Future which cannot be inspected until the block completes.

Examples:

Normal usage

ret = dbclient.hset(key, field, value)
Familia.success?(ret)  #=> true (for 0 or 1)

Inside pipeline

pipelined do
  ret = dbclient.hset(key, field, value)
  Familia.success?(ret)  #=> Redis::Future (passthrough)
end

Parameters:

  • ret (Integer, Redis::Future)

    The return value from a Redis command

Returns:

  • (Boolean, Redis::Future)

    true/false for concrete values, passthrough for Futures



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

def success?(ret)
  ret.is_a?(Redis::Future) ? ret : (ret.zero? || ret.positive?)
end