Class: LoggedStruct

Inherits:
OpenStruct
  • Object
show all
Defined in:
lib/logged_struct.rb

Overview

LoggedStruct behaves like OpenStruct but logs all get and set operations on its attributes, providing visibility into how the object is used.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = nil, logger: nil, log_level: :debug) ⇒ LoggedStruct

Initializes a new LoggedStruct.

Parameters:

  • hash (Hash) (defaults to: nil)

    initial values.

  • logger (Logger) (defaults to: nil)

    logger instance; one is created if not provided.

  • log_level (Symbol) (defaults to: :debug)

    logging level (:debug, :info, etc.).



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/logged_struct.rb', line 19

def initialize(hash = nil, logger: nil, log_level: :debug)
  @log_buffer = StringIO.new
  @custom_log_level = log_level.to_sym
  @logger = logger || Logger.new($stdout)
  @logger.level = Logger.const_get(@custom_log_level.to_s.upcase)
  @logger.formatter ||= proc { |severity, datetime, progname, msg| "#{msg}\n" }
  
  super({})
  
  (hash || {}).each { |key, value| self[key] = value }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Delegates missing method calls.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/logged_struct.rb', line 78

def method_missing(method, *args, &block)
  method_name = method.to_s
  if method_name.end_with?('=')
    attribute = method_name.chop
    self[attribute] = args.first
  else
    # If arguments are provided, delegate to super to raise NoMethodError.
    if args.empty?
      self[method_name]
    else
      super
    end
  end
end

Instance Attribute Details

#log_bufferObject (readonly)

Returns the value of attribute log_buffer.



13
14
15
# File 'lib/logged_struct.rb', line 13

def log_buffer
  @log_buffer
end

#loggerObject (readonly)

Returns the value of attribute logger.



13
14
15
# File 'lib/logged_struct.rb', line 13

def logger
  @logger
end

Instance Method Details

#[](name) ⇒ Object

Logs attribute retrieval.



32
33
34
35
36
# File 'lib/logged_struct.rb', line 32

def [](name)
  value = super
  log_get_operation(name.to_s, value)
  value
end

#[]=(name, value) ⇒ Object

Logs attribute setting.



39
40
41
42
43
44
# File 'lib/logged_struct.rb', line 39

def []=(name, value)
  log_set_operation(name.to_s, value)
  super
  ensure_logging_methods(name.to_sym)
  value
end

#ensure_logging_methods(name) ⇒ Object

Installs logging versions of getters and setters.

Parameters:

  • name (Symbol)

    attribute name.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/logged_struct.rb', line 56

def ensure_logging_methods(name)
  eigen = singleton_class
  if eigen.method_defined?(name) && eigen.instance_method(name).owner == eigen
    eigen.send(:remove_method, name)
  end
  if eigen.method_defined?("#{name}=") && eigen.instance_method("#{name}=").owner == eigen
    eigen.send(:remove_method, "#{name}=")
  end

  eigen.define_method(name) do
    value = @table[name]
    log_get_operation(name.to_s, value)
    value
  end

  eigen.define_method("#{name}=") do |value|
    log_set_operation(name.to_s, value)
    @table[name] = value
  end
end

#log_contentObject

Returns the internal log buffer.



108
109
110
# File 'lib/logged_struct.rb', line 108

def log_content
  @log_buffer.string
end

#new_ostruct_member(name) ⇒ Object

Overrides OpenStruct’s member creation to install logging methods.



47
48
49
50
51
52
# File 'lib/logged_struct.rb', line 47

def new_ostruct_member(name)
  name = name.to_sym
  result = super
  ensure_logging_methods(name)
  result
end

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Checks if a method exists.

Returns:

  • (Boolean)


94
95
96
97
98
# File 'lib/logged_struct.rb', line 94

def respond_to_missing?(method, include_private = false)
  method_name = method.to_s
  return true if method_name.end_with?('=')
  @table.key?(method) || super
end

#to_hObject

Logs conversion to a hash.



101
102
103
104
105
# File 'lib/logged_struct.rb', line 101

def to_h
  hash = super
  log_message("Converting LoggedStruct to Hash: #{hash.inspect}")
  hash
end