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
Represents a single line of code of a given source file
This object contains metadata about the line such as amount of indentation, if it is empty or not, and lexical data, such as if it has an ‘end` or a keyword in it.
Visibility of lines can be toggled off. Marking a line as invisible indicates that it should not be used for syntax checks. It’s functionally the same as commenting it out.
Example:
line = CodeLine.from_source("def foo\n").first line.number => 1 line.empty? # => false line.visible? # => true line.mark_invisible line.visible? # => false
Searches code for a syntax error
There are three main phases in the algorithm:
Sanitize/format input source
Search for invalid blocks
Format invalid blocks into something meaninful
This class handles the part.
The bulk of the heavy lifting is done in:
- CodeFrontier (Holds information for generating blocks and determining if we can stop searching) - ParseBlocksFromLine (Creates blocks into the frontier) - BlockExpand (Expands existing blocks to search more code)
## Syntax error detection
When the frontier holds the syntax error, we can stop searching
search = CodeSearch.new(<<~EOM) def dog def lol end EOM search.call search.invalid_blocks.map(&:to_s) # => # => ["def lol\n"]
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
Ripper.lex
is not guaranteed to lex the entire source document
lex = LexAll.new
(source: source) lex.each do |value|
puts value.line
end
Value object for accessing lex values
This lex:
[1, 0], :on_ident, "describe", CMDARG
Would translate into:
lex.line # => 1 lex.type # => :on_indent lex.token # => "describe"
Not a URI
.
URI
is valid, bad usage is not.
Raised on attempt to Ractor#take
if there was an uncaught exception in the Ractor
. Its cause
will contain the original exception, and ractor
is the original ractor it was raised in.
r = Ractor.new { raise "Something weird happened" } begin r.take rescue => e p e # => #<Ractor::RemoteError: thrown by remote Ractor.> p e.ractor == r # => true p e.cause # => #<RuntimeError: Something weird happened> end
Raised on an attempt to access an object which was moved in Ractor#send
or Ractor.yield
.
r = Ractor.new { sleep } ary = [1, 2, 3] r.send(ary, move: true) ary.inspect # Ractor::MovedError (can not send any methods to a moved object)
exception to wait for reading. see IO.select
.
exception to wait for writing. see IO.select
.
When using Psych.load
to deserialize a YAML
document, the document is translated to an intermediary AST. That intermediary AST is then translated in to a Ruby object graph.
In the opposite direction, when using Psych.dump
, the Ruby object graph is translated to an intermediary AST which is then converted to a YAML
document.
Psych::Nodes
contains all of the classes that make up the nodes of a YAML
AST. You can manually build an AST and use one of the visitors (see Psych::Visitors
) to convert that AST to either a YAML
document or to a Ruby object graph.
Here is an example of building an AST that represents a list with one scalar:
# Create our nodes stream = Psych::Nodes::Stream.new doc = Psych::Nodes::Document.new seq = Psych::Nodes::Sequence.new scalar = Psych::Nodes::Scalar.new('foo') # Build up our tree stream.children << doc doc.children << seq seq.children << scalar
The stream is the root of the tree. We can then convert the tree to YAML:
stream.to_yaml => "---\n- foo\n"
Or convert it to Ruby:
stream.to_ruby => [["foo"]]
YAML
AST Requirements A valid YAML
AST must have one Psych::Nodes::Stream
at the root. A Psych::Nodes::Stream
node must have 1 or more Psych::Nodes::Document
nodes as children.
Psych::Nodes::Document
nodes must have one and only one child. That child may be one of:
Psych::Nodes::Sequence
and Psych::Nodes::Mapping
nodes may have many children, but Psych::Nodes::Mapping
nodes should have an even number of children.
All of these are valid children for Psych::Nodes::Sequence
and Psych::Nodes::Mapping
nodes:
Psych::Nodes::Scalar
and Psych::Nodes::Alias
are both terminal nodes and should not have any children.
The GC
profiler provides access to information on GC
runs including time, length and object space size.
Example:
GC::Profiler.enable require 'rdoc/rdoc' GC::Profiler.report GC::Profiler.disable
See also GC.count
, GC.malloc_allocated_size
and GC.malloc_allocations
The Observable
module extended to DRb
. See Observable
for details.
Extends command line arguments array (ARGV) to parse itself.
Acceptable argument classes. Now contains DecimalInteger, OctalInteger and DecimalNumeric. See Acceptable argument classes (in source code).
Raised by Encoding
and String
methods when the source encoding is incompatible with the target encoding.