Class: DeepCover::CustomRequirer

Inherits:
Object
  • Object
show all
Defined in:
lib/deep_cover/custom_requirer.rb

Defined Under Namespace

Classes: LoadPathsSubset

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(load_paths: $LOAD_PATH, loaded_features: $LOADED_FEATURES, lookup_paths: nil, &filter) ⇒ CustomRequirer

Returns a new instance of CustomRequirer.



47
48
49
50
51
52
53
54
# File 'lib/deep_cover/custom_requirer.rb', line 47

def initialize(load_paths: $LOAD_PATH, loaded_features: $LOADED_FEATURES, lookup_paths: nil, &filter)
  @load_paths = load_paths
  lookup_paths ||= Dir.getwd
  lookup_paths = Array(lookup_paths)
  @load_paths_subset = LoadPathsSubset.new(load_paths: load_paths, lookup_paths: lookup_paths) unless lookup_paths.include? '/'
  @loaded_features = loaded_features
  @filter = filter
end

Instance Attribute Details

#filterObject (readonly)

Returns the value of attribute filter.



46
47
48
# File 'lib/deep_cover/custom_requirer.rb', line 46

def filter
  @filter
end

#load_pathsObject (readonly)

Returns the value of attribute load_paths.



46
47
48
# File 'lib/deep_cover/custom_requirer.rb', line 46

def load_paths
  @load_paths
end

#loaded_featuresObject (readonly)

Returns the value of attribute loaded_features.



46
47
48
# File 'lib/deep_cover/custom_requirer.rb', line 46

def loaded_features
  @loaded_features
end

Instance Method Details

#load(path) ⇒ Object

Homemade #load to be able to instrument the code before it gets executed. Note, this doesn’t support the ‘wrap` parameter that ruby’s #load has. Same return/throw as CustomRequirer#require, except: Cannot return false since #load doesn’t care about a file already being executed.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/deep_cover/custom_requirer.rb', line 111

def load(path)
  found_path = resolve_path(path)

  if found_path.nil?
    # #load has a final fallback of always trying relative to current work directory of process
    possible_path = File.absolute_path(path)
    found_path = possible_path if (@load_paths_subset || File).exist?(possible_path)
  end

  throw :use_fallback, :not_found unless found_path

  cover_and_execute(found_path)

  true
end

#require(path) ⇒ Object

Homemade #require to be able to instrument the code before it gets executed. Returns true when everything went right. (Same as regular ruby) Returns false when the found file was already required. (Same as regular ruby) Throws :use_fallback in case caller should delegate to the default #require. Reasons given could be:

- :not_found if the file couldn't be found.
- :cover_failed if DeepCover couldn't apply instrumentation the file found.
- :not_supported for files that are not supported (such as ike .so files)
- :skipped if the filter block returned `true`

Exceptions raised by the required code bubble up as normal.

It is *NOT* recommended to simply delegate to the default #require, since it
might not be safe to run part of the code again.


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/deep_cover/custom_requirer.rb', line 88

def require(path)
  ext = File.extname(path)
  throw :use_fallback, :not_supported if ext == '.so'
  path += '.rb' if ext != '.rb'
  return false if @loaded_features.include?(path)

  found_path = resolve_path(path)

  throw :use_fallback, :not_found unless found_path
  return false if @loaded_features.include?(found_path)

  throw :use_fallback, :skipped if filter && filter.call(found_path)

  cover_and_execute(found_path)

  @loaded_features << found_path
  true
end

#resolve_path(path) ⇒ Object

Returns a path to an existing file or nil if none can be found. The search follows how ruby search for files using the $LOAD_PATH

An absolute path is returned directly if it exists, otherwise nil is returned without searching anywhere else.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/deep_cover/custom_requirer.rb', line 61

def resolve_path(path)
  path = File.absolute_path(path) if path.start_with?('./', '../')

  abs_path = File.absolute_path(path)
  if path == abs_path
    path if (@load_paths_subset || File).exist?(path)
  else
    (@load_paths_subset || self).load_paths.each do |load_path|
      possible_path = File.absolute_path(path, load_path)
      return possible_path if (@load_paths_subset || File).exist?(possible_path)
    end
    nil
  end
end