Class: Ladybug::ObjectManager

Inherits:
Object
  • Object
show all
Defined in:
lib/ladybug/object_manager.rb

Overview

This class:

  • serializes objects for display in the Chrome UI

  • maintains references to all objects for which it has given out IDs for; this ensures they don’t get GC’d and can be dereferenced later by ID.

TODO: Handle Chrome’s “release” APIs to enable releasing references

at some point and avoid too much memory growth

Instance Method Summary collapse

Constructor Details

#initializeObjectManager

Returns a new instance of ObjectManager.



12
13
14
# File 'lib/ladybug/object_manager.rb', line 12

def initialize
  @objects = {}
end

Instance Method Details

#find(id) ⇒ Object

Given an ID, return the object from our registry



17
18
19
# File 'lib/ladybug/object_manager.rb', line 17

def find(id)
  @objects[id]
end

#get_properties(object) ⇒ Object

Ruby objects don’t have properties like JS objects do, so we need to figure out the best properties to show for non-primitives.

We first give the object a chance to tell us its debug properties, then we fall back to handling a bunch of common cases, then finally we give up and just serialize its instance variables.



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
# File 'lib/ladybug/object_manager.rb', line 96

def get_properties(object)
  if object.respond_to?(:chrome_debug_properties)
    get_properties(object.chrome_debug_properties)
  elsif object.is_a? Hash
    object.
      map do |key, value|
        {
          name: key,
          value: serialize(value)
        }
      end.
      reject { |property| property[:value].nil? }
  elsif object.is_a? Array
    object.map.with_index do |element, index|
      {
        name: index.to_s,
        value: serialize(element)
      }
    end

  # TODO: This section is too magical,
  # better to let users just define their own chrome_debug_properties
  # and then add an optional Rails plugin to the gem which
  # monkey patches rails classes.
  elsif object.respond_to?(:to_a)
    get_properties(object.to_a)
  elsif object.respond_to?(:attributes)
    get_properties(object.attributes)
  elsif object.respond_to?(:to_hash)
    get_properties(object.to_hash)
  elsif object.respond_to?(:to_h)
    get_properties(object.to_h)
  else
    ivar_hash = object.instance_variables.each_with_object({}) do |ivar, hash|
      hash[ivar] = object.instance_variable_get(ivar)
    end

    get_properties(ivar_hash)
  end
end

#register(object) ⇒ Object

Given an object, register it in our internal state and return an ID for it



23
24
25
26
27
# File 'lib/ladybug/object_manager.rb', line 23

def register(object)
  object_id = SecureRandom.uuid
  @objects[object_id] = object
  object_id
end

#serialize(object) ⇒ Object

Convert a Ruby object to a hash representing a Chrome RemoteObject chromedevtools.github.io/devtools-protocol/tot/Runtime#type-RemoteObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ladybug/object_manager.rb', line 31

def serialize(object)
  case object
  when String
    {
      type: "string",
      value: object,
      description: object
    }
  when Numeric
    {
      type: "number",
      value: object,
      description: object.to_s
    }
  when TrueClass, FalseClass
    {
      type: "boolean",
      value: object,
      description: object.to_s
    }
  when Symbol
    {
      type: "symbol",
      value: object,
      description: object.to_s
    }
  when Array
    result = {
      type: "object",
      className: object.class.to_s,
      description: "Array(#{object.length})",
      objectId: register(object),
      subtype: "array"
    }

    result.merge!(
      preview: result.merge(
        overflow: false,
        properties: get_properties(object)
      )
    )

    result
  when nil
    {
      type: "object",
      subtype: "null",
      value: nil
    }
  else
    {
      type: "object",
      className: object.class.to_s,
      description: object.to_s,
      objectId: register(object)
    }
  end
end