use tree_sitter::Node;
use crate::cop::layout::end_align;
use crate::cop::{Cop, CopConfig};
use crate::correction::Correction;
use crate::diagnostic::Diagnostic;
use crate::parse::source::SourceFile;
pub struct EndAlignment;
fn base_name(kind: &str) -> &'static str {
match kind {
"class" => "class",
"module" => "module",
"if" => "if",
"unless" => "unless",
"while" => "while",
"until" => "until",
"case" => "case",
_ => "def",
}
}
impl Cop for EndAlignment {
fn name(&self) -> &'static str {
"Layout/EndAlignment"
}
fn supports_autocorrect(&self) -> bool {
true
}
fn interested_node_kinds(&self) -> &'static [&'static str] {
&[
"class",
"module",
"if",
"unless",
"while",
"until",
"case",
]
}
fn check_node(
&self,
source: &SourceFile,
node: Node<'_>,
config: &CopConfig,
diagnostics: &mut Vec<Diagnostic>,
mut corrections: Option<&mut Vec<Correction>>,
) {
end_align::check_end(
self,
source,
node,
base_name(node.kind()),
config.get_str("EnforcedStyleAlignWith", "keyword"),
diagnostics,
&mut corrections,
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testutil::run_cop_full_with_config;
use std::collections::HashMap;
crate::cop_fixture_tests!(EndAlignment, "cops/layout/end_alignment");
fn variable_config() -> CopConfig {
CopConfig {
options: HashMap::from([(
"EnforcedStyleAlignWith".into(),
serde_yml::Value::String("variable".into()),
)]),
..CopConfig::default()
}
}
#[test]
fn variable_style_operator_assignment_if_no_offense() {
let diags = run_cop_full_with_config(
&EndAlignment,
b" trades.each do |t|\n total_from += if cr.from_currency_id == t.currency_id\n t.volume\n else\n t.funds\n end\n end\n",
variable_config(),
);
assert!(
diags.is_empty(),
"variable style should align end with += assignment: {:?}",
diags
);
}
#[test]
fn variable_style_shovel_if_no_offense() {
let diags = run_cop_full_with_config(
&EndAlignment,
b" warnings << if initiator\n t('msg')\n else\n t('other')\n end\n",
variable_config(),
);
assert!(
diags.is_empty(),
"variable style should align end with << receiver: {:?}",
diags
);
}
#[test]
fn variable_style_case_method_arg_no_offense() {
let diags = run_cop_full_with_config(
&EndAlignment,
b"def sorted(key = DEFAULT_SORT, shares: nil, pin: nil)\n pin_first(case self.class.sort_key(key)\n when \"name\" then 1\n else 2\n end, pin)\nend\n",
variable_config(),
);
assert!(
diags.is_empty(),
"variable style should align end with call for case arg: {:?}",
diags
);
}
#[test]
fn variable_style_case_command_arg_no_offense() {
let diags = run_cop_full_with_config(
&EndAlignment,
b"test case a when b\nend\n",
variable_config(),
);
assert!(
diags.is_empty(),
"variable style should align end with command for case arg: {:?}",
diags
);
}
#[test]
fn variable_style_case_arg_keyword_aligned_is_offense() {
let diags = run_cop_full_with_config(
&EndAlignment,
b"test case a when b\n end\n",
variable_config(),
);
assert_eq!(
diags.len(),
1,
"end aligned with case is bad under variable: {:?}",
diags
);
}
}