Class: Contrast::Utils::ClassUtil
- Defined in:
- lib/contrast/utils/class_util.rb
Overview
Utility methods for exploring the complete space of Objects
Class Method Summary collapse
-
.descendants(mod) ⇒ Array<Module>
Given a module, return all of its descendants.
-
.prepended?(mod, ancestors = nil) ⇒ Boolean
some classes have had things prepended to them, like Marshal in Rails 5 and higher.
-
.prepended_method?(mod, method_policy) ⇒ Boolean
return true if the given method is overwritten by one of the ancestors in the ancestor change that comes before the given module.
-
.to_contrast_string(object) ⇒ String
Return a String representing the object invoking this method in the form expected by our dataflow events.
-
.truly_defined?(name) ⇒ Boolean
The method const_defined? can cause autoload, which is bad for us.
Class Method Details
.descendants(mod) ⇒ Array<Module>
Given a module, return all of its descendants
16 17 18 |
# File 'lib/contrast/utils/class_util.rb', line 16 def descendants mod ObjectSpace.each_object(mod).to_a end |
.prepended?(mod, ancestors = nil) ⇒ Boolean
some classes have had things prepended to them, like Marshal in Rails 5 and higher. Their ActiveSupport::MarshalWithAutoloading will break our alias patching approach, as will any other prepend on something that we touch. Prepend and Alias are inherently incompatible monkey patching approaches. As such, we need to know if something has been prepended to.
31 32 33 34 |
# File 'lib/contrast/utils/class_util.rb', line 31 def prepended? mod, ancestors = nil ancestors ||= mod.ancestors ancestors[0] != mod end |
.prepended_method?(mod, method_policy) ⇒ Boolean
return true if the given method is overwritten by one of the ancestors in the ancestor change that comes before the given module
38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/contrast/utils/class_util.rb', line 38 def prepended_method? mod, method_policy target_module = determine_target_class mod, method_policy.instance_method ancestors = target_module.ancestors return false unless prepended?(target_module, ancestors) ancestors.each do |ancestor| break if ancestor == target_module methods = ancestor.instance_methods(false) return true if methods.include?(method_policy.method_name) end false end |
.to_contrast_string(object) ⇒ String
Return a String representing the object invoking this method in the form expected by our dataflow events.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/contrast/utils/class_util.rb', line 58 def to_contrast_string object # Only treat object like a string if it actually is a string # some subclasses of String override string methods we depend on if object.cs__class == String cached = to_cached_string(object) return cached if cached object.dup elsif object.cs__is_a?(Symbol) ":#{ object }" elsif object.cs__is_a?(Numeric) object.to_s elsif object.cs__is_a?(Module) || object.cs__is_a?(Class) "#{ object.cs__name }@#{ object.__id__ }" elsif object.cs__is_a?(Regexp) object.source else "#{ object.cs__class.cs__name }@#{ object.__id__ }" end end |
.truly_defined?(name) ⇒ Boolean
The method const_defined? can cause autoload, which is bad for us. The method autoload? doesn’t traverse namespaces. This method lets us provide a constant, as a String, and parse it to determine if it has been truly truly defined, meaning it existed before this method was invoked, not as a result of it.
This is required to handle a bug in Ruby prior to 2.7.0. When we drop support for 2.6.X, we should remove this code. bugs.ruby-lang.org/issues/10741
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/contrast/utils/class_util.rb', line 90 def truly_defined? name return false unless name segments = name.split(Contrast::Utils::ObjectShare::DOUBLE_COLON) previous_module = Module segments.each do |segment| return false if previous_module.cs__autoload?(segment) return false unless previous_module.cs__const_defined?(segment) previous_module = previous_module.cs__const_get(segment) end true rescue NameError # account for nonsense / poorly formatted constants false end |