개그 지령'dont'를 만들었어요.
cargo install dont
(현재 구축된 바이너리나 각종 발표 소프트웨어 패키지가 존재하지 않습니다. 공헌을 환영합니다!)이거 뭐야?
이름과 같이 지정한 처리를 실행하지 않는 명령입니다.예컨대
dont mkdir foo
foo를 만들지 않습니다.dont 명령이 반드시'아무것도 하지 않는다'는 것은 아니다.특정한 모델에 대해 사용자의 의도를 고려하여 특별히 처리하다.readme에 몇 가지 예가 쓰여 있다.모든 모드를 알고 싶은 사람은 소스 코드를 참조하세요.
왜 이 타이밍에 공개됐냐면요.
만우절 대목으로 삼고 싶었는데 다른 농담거리와도 충돌이 있을 것 같아 일찍 공개하기로 했다.
설치 방법
기본적으로'출락'으로 마무리되지만, 실장에는 몇 가지 노하우가 있으니 다음은 소개한다.
-- 처리
이 명령은 명령행 분석기clap를 사용하여 부품 파라미터를 선택할 수 있습니다.현재
--help
와 --version
등clap의 기본 명령만 실현되었다.이 경우
-
로 시작하는 문자열을 하위 명령의 일부분으로 지정하려면 곤란합니다.이런 상황에서 대책으로 --
영패는'나머지는 모두 위치 파라미터'라는 습관을 사용했다.# 以下の2つは同じ意味
dont ls
dont -- ls
# 以下の2つは別の意味になる
dont --help # ヘルプを表示
dont -- --help # "--help" はdontに対する指定の一部として解釈される
clap은 기본적으로 이런--
에 대해 설명하지만 그 다음에 등장하는--
도 다 먹는 문제가 있다.dont -- ls # 引数は ["ls"]
dont rm -- -r # 引数は ["rm", "--", "-r"] になってほしい
# ↑デフォルトでは ["rm", "-r"] になってしまう
dont
에서 보듯이 위치 파라미터를 명령으로 재해석하려면 --
이렇게 식용되면 사용자의 의도에 어긋날 수 있다.따라서 지정#[clap(allow_hyphen_values = true)]
을 통해 최초의 위치 매개 변수 이후의 모든 매개 변수는 위치 매개 변수로 해석된다.exec
dont
일정한 조건하에서 명령을 호출한다.이때 제어를 dont
로 복구할 필요가 없기 때문에 유닉스계 환경execve(2)에서 자체로 교체하는 것이 좋다.일반적으로 이것은 다음과 같은 이유가 있다.dont
명령을 진지하게 사용하는 사람은 없지만 얻기 어려운 기회이기 때문에 예의를 지키기 위해dont
fork-exec를 사용하지 않고 exec로 명령을 시작합니다.그러나 모든 OS에서 exec를 사용할 수 있는 것은 아니기 때문에 다음은 OS로 상황을 구분한다.cfg_if! {
if #[cfg(unix)] {
// unix系環境の場合はexecで起動し、dontコマンドに制御を戻さない
use std::os::unix::process::CommandExt;
result = Err(command.exec());
} else {
// unix系以外の環境の場合はサブプロセスとして起動する
result = command.spawn();
}
}
테스트
dont
농담 지령이라고 하지만 그에 상응하는 복잡한 처리도 포함한다.앞으로 기능을 추가할 여지가 있기 때문에 시험을 써보려고 합니다.dont
중 아래 부분은 일정한 복잡성이 있기 때문에 테스트 대상에 포함된다.exec
프로그램이 끝났기 때문에 단원 테스트에서 실행하기 어렵다.또 환경에 따라 실제 사용하는 지령도 다르지만 이를 배려하고 싶지 않다.이 부분은 자주 변경되는 곳이 아니기 때문에 수지가 맞지 않는다.// dontコマンドの中核処理はこの値を返す
#[derive(Debug, Clone, PartialEq, Eq)]
enum Conclusion {
Exit(i32),
Exec(Vec<OsString>),
}
이것은 마지막으로 실행해야 할 처리를 나타낸다.실제 구축은 다음과 같은 처리를 지원한다.Conclusion::Exit
→ std::process::exit
Conclusion::Exec
→ std::os::unix::process::CommandExt::exec
한편, 반복되는 외부 처리를 테스트할 수 있도록 이동 가능한 다음trait를 정의했다.
// 外界に問い合わせるときはこの値を使う。
// 現在はコマンドの存在判定処理だけが定義されている。
trait Controller {
fn has_command(&self, name: &str) -> bool;
}
실제 구축에서 처리를 which crate에 인계하고dont 명령에서 특수 처리를 하지 않았다.그래서 이 부분은 테스트할 수 없습니다.dont 명령의 핵심 처리
execute
함수로 이 실례를 받아들인다.이번에는 정적 플로피 디스크를 사용했기 때문에 비용도 들지 않았다.// ctl が外界へのインターフェースになっている
fn execute<C: Controller>(ctl: &C, args: &Args) -> Conclusion { /* ... */ }
그러면 이렇게 외부 환경에 의존하는 처리 인터페이스화를 테스트할 때 다른 실시 방식으로 바꿀 수 있고 교체 방법으로 대체적으로 다음과 같은 두 가지 방법이 있다.has_command
입력과 출력은 모두 간단하고 필요한 최소한이라고만 불리며 불릴 때 기대하는 행위는 테스트 사례에 따라 대부분 다르다.나는 마크가 비교적 적합하다고 생각해서 마크를 제공하기로 결정했다.Rust에서 mock을 제공하는 라이브러리가 여러 개였는데mockall 저자의 꾸준함을 느낄 수 있고 평가도 좋아서 이번에 사용하기로 했다.
mockall에서attribute macro
#[automock]
를traait에 추가하면mock을 생성할 수 있습니다.실제 구축에서 모듈화할 필요가 없기 때문에 mockall는dev-dependenciescfg_attr
에 미리 넣고 테스트할 때만 모듈을 생성하여 실현합니다.#[cfg_attr(test, mockall::automock)] // mock実装を生成する
trait Controller {
fn has_command(&self, name: &str) -> bool;
}
trait명에 Mock
의 이름을 더한 struct(이 경우 MockController
) 생성 모듈 설치.응답이 없는 모듈은 다음과 같이 생성할 수 있습니다.// 何も応答しない (常にpanicする)
let ctl = MockController::new();
이것을 교부하면 불려오지 않았음을 확인할 수 있습니다has_command
.has_command
의 호출을 테스트하려면 expect_*
을 미리 불러주세요.// has_command("sl") に対してtrueを返すよう設定
let mut ctl = MockController::new();
ctl.expect_has_command().with(mockall::predicate::eq("sl")).returning(|_| true);
최후
dont
여러분의 공헌을 환영하라고 명령합니다.Rust에 뭔가를 쓰고 싶은 사람은 반드시 재미있는 도안을 추가한 홍보를 해 보세요.또한 qnighy/dont를 좋아한다면 스타를 더해 격려할 수 있다.
Reference
이 문제에 관하여(개그 지령'dont'를 만들었어요.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/qnighy/articles/9add3ece5cbf16텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)