lib/slim_lint/sexp.rb in slim_lint-0.2.0 vs lib/slim_lint/sexp.rb in slim_lint-0.3.0
- old
+ new
@@ -6,23 +6,26 @@
class Sexp < Array
# Stores the line number of the code in the original document that
# corresponds to this Sexp.
attr_accessor :line
- # Creates an {Sexp} from the given {Array}-based Sexp, performing a deep
- # copy.
- def initialize(sexp)
- sexp.each do |child|
- item =
- case child
- when Array
- Sexp.new(child)
- else
- child
- end
-
- push(item)
+ # 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]
+ 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
# Returns whether this {Sexp} matches the given Sexp pattern.
#
@@ -40,49 +43,59 @@
# [: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 [Sexp]
+ # @param sexp_pattern [Object,Array]
# @return [Boolean]
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 unless length >= sexp_pattern.length
+ return false unless sexp_pattern.is_a?(Array) && length >= sexp_pattern.length
sexp_pattern.each_with_index do |sub_pattern, index|
- case sub_pattern
- when Array
- return false unless self[index].match?(sub_pattern)
- else
- return false unless self[index] == sub_pattern
- end
+ return false unless self[index].match?(sub_pattern)
end
true
end
+ # Returns pretty-printed representation of this S-expression.
+ #
+ # @return [String]
+ def inspect
+ display
+ end
+
+ protected
+
+ # Pretty-prints this Sexp in a form that is more readable.
+ #
+ # @param depth [Integer] indentation level to display Sexp at
+ # @return [String]
def display(depth = 1) # rubocop:disable Metrics/AbcSize
indentation = ' ' * 2 * depth
- output = indentation
output = '['
- output << "\n"
each_with_index do |nested_sexp, index|
+ output << "\n"
output += indentation
- case nested_sexp
- when Sexp
+ if nested_sexp.is_a?(SlimLint::Sexp)
output += nested_sexp.display(depth + 1)
else
output += nested_sexp.inspect
end
- if index < length - 1
- output += ",\n"
- end
+ # Add trailing comma unless this is the last item
+ output += ',' if index < length - 1
end
- output << "\n"
- output << ' ' * 2 * (depth - 1)
+
+ output << "\n" << ' ' * 2 * (depth - 1) unless empty?
output << ']'
output
end
end