Class: Contrast::Agent::ClassReopener Deprecated

Inherits:
Object
  • Object
show all
Includes:
Components::Interface
Defined in:
lib/contrast/agent/class_reopener.rb

Overview

Deprecated.

Changes to this class are discouraged as this approach is being phased out with support for those language versions.

TODO: RUBY-714 remove w/ EOL of 2.5

Constant Summary collapse

END_NEW_LINE =
"end\n"
PROTECTED_WITH_NEW_LINE =
"protected\n"
PRIVATE_WITH_NEW_LINE =
"private\n"
CLASS_SELF_LINE =
"class << self\n"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Components::Interface

included

Constructor Details

#initialize(module_data) ⇒ ClassReopener

Returns a new instance of ClassReopener.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/contrast/agent/class_reopener.rb', line 50

def initialize module_data
  @class_module_path = module_data.name
  clazz = module_data.mod
  @is_class = clazz.is_a?(Class)
  @public_instance_methods = []
  @protected_instance_methods = []
  @private_instance_methods = []
  @public_singleton_methods = []
  @files = {}
  @name_space = []
  @class_name = nil
  @locations = Hash.new { |h, k| h[k] = [] }
  gather_modules
end

Instance Attribute Details

#class_module_pathObject (readonly)

Returns the value of attribute class_module_path.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def class_module_path
  @class_module_path
end

#class_nameObject (readonly)

Returns the value of attribute class_name.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def class_name
  @class_name
end

#filesObject (readonly)

Returns the value of attribute files.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def files
  @files
end

#is_classObject (readonly)

Returns the value of attribute is_class.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def is_class
  @is_class
end

#locationsObject (readonly)

Returns the value of attribute locations.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def locations
  @locations
end

#name_spaceObject (readonly)

Returns the value of attribute name_space.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def name_space
  @name_space
end

#private_instance_methodsObject (readonly)

Returns the value of attribute private_instance_methods.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def private_instance_methods
  @private_instance_methods
end

#protected_instance_methodsObject (readonly)

Returns the value of attribute protected_instance_methods.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def protected_instance_methods
  @protected_instance_methods
end

#public_instance_methodsObject (readonly)

Returns the value of attribute public_instance_methods.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def public_instance_methods
  @public_instance_methods
end

#public_singleton_methodsObject (readonly)

Returns the value of attribute public_singleton_methods.



47
48
49
# File 'lib/contrast/agent/class_reopener.rb', line 47

def public_singleton_methods
  @public_singleton_methods
end

Instance Method Details

#commit_patchesObject

Evaluate the patches that have been staged for this class, replacing the method definitions with those our rewrite.



103
104
105
106
107
108
109
110
111
# File 'lib/contrast/agent/class_reopener.rb', line 103

def commit_patches
  with_contrast_scope do
    return unless staged_changes?

    content = build_content
    valid = Ripper.sexp(content)
    unbound_eval(class_name, content) if !!valid && !class_name.empty?
  end
end

#source_code(location, method_name) ⇒ String?

Find the sourcecode of the method at the given location and return it if it is complete and compilable.

Parameters:

  • location (Array<String, Integer>)

    the result of a Method#source_location call

  • method_name (Symbol)

    the name of the method defined at the given location

Returns:

  • (String, nil)

    the code defining the method or nil if no valid code could be found.



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
# File 'lib/contrast/agent/class_reopener.rb', line 122

def source_code location, method_name
  file_name = location[0]
  line_number = location[1]
  return unless file_contents_available?(file_name, line_number)

  files[file_name] = File.readlines(file_name) unless files.key?(file_name)
  lines = files[file_name]
  code = +''
  # location#line_number is 1 based, arrays are 0 based
  line_number -= 1
  lines[line_number..-1].each do |line|
    code << line
    next unless compiles?(code)
    break if complete?(code)
  end
  unless complete?(code) && compiles?(code)
    logger.warn(
        'Failed to determine sourcecode for rewriting.',
        file: file_name,
        method: method_name,
        line_number: line_number)
    return
  end
  code
end

#staged_changes?Boolean

Indicates if any methods were rewritten for this class.

Returns:

  • (Boolean)


68
69
70
71
72
73
# File 'lib/contrast/agent/class_reopener.rb', line 68

def staged_changes?
  public_singleton_methods.any? ||
      public_instance_methods.any? ||
      protected_instance_methods.any? ||
      private_instance_methods.any?
end

#written_from_location!(source_location) ⇒ Boolean

Marks that this class was written from the given location.

Parameters:

  • source_location (Array<String, Integer>)

    the result of a Method#source_location call

Returns:

  • (Boolean)


93
94
95
96
97
98
99
# File 'lib/contrast/agent/class_reopener.rb', line 93

def written_from_location! source_location
  return false unless source_location

  file = source_location[0]
  location = source_location[1]
  locations[file] << location
end

#written_from_location?(source_location) ⇒ Boolean

Indicates if this class was written from the given location.

Parameters:

  • source_location (Array<String, Integer>)

    the result of a Method#source_location call

Returns:

  • (Boolean)


80
81
82
83
84
85
86
# File 'lib/contrast/agent/class_reopener.rb', line 80

def written_from_location? source_location
  return false unless source_location

  file = source_location[0]
  location = source_location[1]
  locations[file].include?(location)
end