Given a set of Gem::Dependency
objects as needed
and a way to query the set of available specs via set
, calculates a set of ActivationRequest
objects which indicate all the specs that should be activated to meet the all the requirements.
S3URISigner
implements AWS SigV4 for S3 Source to avoid a dependency on the aws-sdk-* gems More on AWS SigV4: docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
SpecFetcher
handles metadata updates from remote gem repositories.
A TargetConfig is a wrapper around an RbConfig
object that provides a consistent interface for querying configuration for *deployment target platform*, where the gem being installed is intended to run on.
The TargetConfig is typically created from the RbConfig
of the running Ruby process, but can also be created from an RbConfig
file on disk for cross- compiling gems.
An Uninstaller
.
The uninstaller fires pre and post uninstall hooks. Hooks can be added either through a rubygems_plugin.rb file in an installed gem or via a rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb file. See Gem.pre_uninstall
and Gem.post_uninstall
for details.
The UriFormatter
handles URIs from user-input and escaping.
uf = Gem::UriFormatter.new 'example.com' p uf.normalize #=> 'http://example.com'
This class is useful for exploring contents before and after a block
It searches above and below the passed in block to match for whatever criteria you give it:
Example:
def dog # 1 puts "bark" # 2 puts "bark" # 3 end # 4 scan = AroundBlockScan.new( code_lines: code_lines block: CodeBlock.new(lines: code_lines[1]) ) scan.scan_while { true } puts scan.before_index # => 0 puts scan.after_index # => 3
This class is responsible for taking a code block that exists at a far indentaion and then iteratively increasing the block so that it captures everything within the same indentation block.
def dog puts "bow" puts "wow" end
block = BlockExpand.new
(code_lines: code_lines)
.call(CodeBlock.new(lines: code_lines[1]))
puts block.to_s # => puts “bow”
puts "wow"
Once a code block has captured everything at a given indentation level then it will expand to capture surrounding indentation.
block = BlockExpand.new
(code_lines: code_lines)
.call(block)
block.to_s # => def dog
puts "bow" puts "wow" end
Multiple lines form a singular CodeBlock
Source code is made of multiple CodeBlocks.
Example:
code_block.to_s # => # def foo # puts "foo" # end code_block.valid? # => true code_block.in_valid? # => false
There are three main phases in the algorithm:
Sanitize/format input source
Search for invalid blocks
Format invalid blocks into something meaningful
The Code frontier is a critical part of the second step
## Knowing where we’ve been
Once a code block is generated it is added onto the frontier. Then it will be sorted by indentation and frontier can be filtered. Large blocks that fully enclose a smaller block will cause the smaller block to be evicted.
CodeFrontier#<<(block) # Adds block to frontier CodeFrontier#pop # Removes block from frontier
## Knowing where we can go
Internally the frontier keeps track of “unvisited” lines which are exposed via ‘next_indent_line` when called, this method returns, a line of code with the highest indentation.
The returned line of code can be used to build a CodeBlock
and then that code block is added back to the frontier. Then, the lines are removed from the “unvisited” so we don’t double-create the same block.
CodeFrontier#next_indent_line # Shows next line CodeFrontier#register_indent_block(block) # Removes lines from unvisited
## Knowing when to stop
The frontier knows how to check the entire document for a syntax error. When blocks are added onto the frontier, they’re removed from the document. When all code containing syntax errors has been added to the frontier, the document will be parsable without a syntax error and the search can stop.
CodeFrontier#holds_all_syntax_errors? # Returns true when frontier holds all syntax errors
## Filtering false positives
Once the search is completed, the frontier may have multiple blocks that do not contain the syntax error. To limit the result to the smallest subset of “invalid blocks” call:
CodeFrontier#detect_invalid_blocks
Outputs code with highlighted lines
Whatever is passed to this class will be rendered even if it is “marked invisible” any filtering of output should be done before calling this class.
DisplayCodeWithLineNumbers.new( lines: lines, highlight_lines: [lines[2], lines[3]] ).call # => 1 2 def cat > 3 Dir.chdir > 4 end 5 end 6
Used for formatting invalid blocks
This class is responsible for generating initial code blocks that will then later be expanded.
The biggest concern when guessing code blocks, is accidentally grabbing one that contains only an “end”. In this example:
def dog begonn # misspelled `begin` puts "bark" end end
The following lines would be matched (from bottom to top):
1) end 2) puts "bark" end 3) begonn puts "bark" end
At this point it has no where else to expand, and it will yield this inner code as a block
Converts a SyntaxError
message to a path
Handles the case where the filename has a colon in it such as on a windows file system: github.com/ruby/syntax_suggest/issues/111
Example:
message = "/tmp/scratch:2:in `require_relative': /private/tmp/bad.rb:1: syntax error, unexpected `end' (SyntaxError)" puts PathnameFromMessage.new(message).call.name # => "/tmp/scratch.rb"
Raised by Timeout.timeout
when the block times out.
Base class for all URI
exceptions.
Not a URI
.
Not a URI
component.
URI
is valid, bad usage is not.
RefError
is raised when a referenced object has been recycled by the garbage collector
Raised when a mathematical function is evaluated outside of its domain of definition.
For example, since cos
returns values in the range -1..1, its inverse function acos
is only defined on that interval:
Math.acos(42)
produces:
Math::DomainError: Numerical argument is out of domain - "acos"