class SlimLint::Sexp

Symbolic expression which represents tree-structured data.

The main use of this particular implementation is to provide a single location for defining convenience helpers when operating on Sexps.

Attributes

line[RW]

Stores the line number of the code in the original document that corresponds to this Sexp.

Public Class Methods

new(array_sexp) click to toggle source

Creates an {Sexp} from the given {Array}-based Sexp.

This provides a convenient way to convert between literal arrays of {Symbol}s and {Sexp}s containing {Atom}s and nested {Sexp}s. These objects all expose a similar API that conveniently allows the two objects to be treated similarly due to duck typing.

@param array_sexp [Array]

# File lib/slim_lint/sexp.rb, line 21
def initialize(array_sexp)
  array_sexp.each do |atom_or_sexp|
    case atom_or_sexp
    when Array
      push Sexp.new(atom_or_sexp)
    else
      push SlimLint::Atom.new(atom_or_sexp)
    end
  end
end

Public Instance Methods

inspect() click to toggle source

Returns pretty-printed representation of this S-expression.

@return [String]

# File lib/slim_lint/sexp.rb, line 71
def inspect
  display
end
match?(sexp_pattern) click to toggle source

Returns whether this {Sexp} matches the given Sexp pattern.

A Sexp pattern is simply an incomplete Sexp prefix.

@example

The following Sexp:

  [:html, :doctype, "html5"]

...will match the given patterns:

  [:html]
  [:html, :doctype]
  [:html, :doctype, "html5"]

Note that nested Sexps will also be matched, so be careful about the cost of matching against a complicated pattern.

@param sexp_pattern [Object,Array] @return [Boolean]

# File lib/slim_lint/sexp.rb, line 52
def match?(sexp_pattern)
  # Delegate matching logic if we're comparing against a matcher
  if sexp_pattern.is_a?(SlimLint::Matcher::Base)
    return sexp_pattern.match?(self)
  end

  # If there aren't enough items to compare then this obviously won't match
  return false unless sexp_pattern.is_a?(Array) && length >= sexp_pattern.length

  sexp_pattern.each_with_index do |sub_pattern, index|
    return false unless self[index].match?(sub_pattern)
  end

  true
end

Protected Instance Methods

display(depth = 1) click to toggle source

Pretty-prints this Sexp in a form that is more readable.

@param depth [Integer] indentation level to display Sexp at @return [String]

# File lib/slim_lint/sexp.rb, line 81
def display(depth = 1) # rubocop:disable Metrics/AbcSize
  indentation = ' ' * 2 * depth
  output = '['.dup

  each_with_index do |nested_sexp, index|
    output << "\n"
    output += indentation

    output +=
      if nested_sexp.is_a?(SlimLint::Sexp)
        nested_sexp.display(depth + 1)
      else
        nested_sexp.inspect
      end

    # Add trailing comma unless this is the last item
    output += ',' if index < length - 1
  end

  output << "\n" << ' ' * 2 * (depth - 1) unless empty?
  output << ']'

  output
end