shard-ameba/src/ameba/source.cr

87 lines
2.1 KiB
Crystal
Raw Normal View History

2017-10-26 17:47:42 +00:00
module Ameba
2017-10-30 20:00:01 +00:00
# An entity that represents a Crystal source file.
2018-06-10 21:15:12 +00:00
# Has path, lines of code and issues reported by rules.
2017-10-26 17:47:42 +00:00
class Source
include InlineComments
2018-06-10 21:15:12 +00:00
include Reportable
2017-10-26 21:01:23 +00:00
2017-11-15 18:49:09 +00:00
# Path to the source file.
2017-12-18 11:06:19 +00:00
getter path : String
2017-11-15 18:49:09 +00:00
# Crystal code (content of a source file).
getter code : String
2017-10-26 17:47:42 +00:00
@lines : Array(String)?
@ast : Crystal::ASTNode?
2017-11-15 18:49:09 +00:00
# Creates a new source by `code` and `path`.
#
# For example:
#
# ```
# path = "./src/source.cr"
# Ameba::Source.new File.read(path), path
# ```
def initialize(@code, @path = "")
2017-10-30 20:00:01 +00:00
end
2021-10-27 04:03:30 +00:00
# Corrects any correctable issues and updates `code`.
# Returns `false` if no issues were corrected.
def correct
corrector = Corrector.new(code)
issues.each(&.correct(corrector))
corrected_code = corrector.process
return false if code == corrected_code
@code = corrected_code
@lines = nil
@ast = nil
true
end
2017-11-15 18:49:09 +00:00
# Returns lines of code splitted by new line character.
# Since `code` is immutable and can't be changed, this
# method caches lines in an instance variable, so calling
# it second time will not perform a split, but will return
# lines instantly.
#
# ```
# source = Ameba::Source.new "a = 1\nb = 2", path
# source.lines # => ["a = 1", "b = 2"]
# ```
#
def lines : Array(String)
@lines ||= code.split('\n')
end
2017-11-15 18:49:09 +00:00
# Returns AST nodes constructed by `Crystal::Parser`.
#
# ```
# source = Ameba::Source.new code, path
# source.ast
# ```
#
def ast : Crystal::ASTNode
@ast ||=
Crystal::Parser.new(code)
.tap(&.wants_doc = true)
.tap(&.filename = path)
.parse
end
getter fullpath : String do
File.expand_path(path)
2017-12-18 11:06:19 +00:00
end
2018-05-29 10:19:00 +00:00
2021-02-03 15:14:03 +00:00
# Returns `true` if the source is a spec file, `false` otherwise.
def spec?
path.ends_with?("_spec.cr")
end
# Returns `true` if *filepath* matches the source's path, `false` if it does not.
2018-05-29 10:19:00 +00:00
def matches_path?(filepath)
path == filepath || path == File.expand_path(filepath)
end
2017-10-26 17:47:42 +00:00
end
end