# 기본 모듈

```{contributors}
:authors: djacu
:editors: fricklerhandwerk
```

모듈이란 무엇입니까?

* 모듈은 속성 집합을 받아 속성 집합을 반환하는 함수입니다.
* 모듈은 옵션을 선언하여 최종 결과에 어떤 속성이 허용되는지 알릴 수 있습니다.
* 모듈은 자신이나 다른 모듈이 선언한 옵션에 값을 정의할 수 있습니다.
* 모듈 시스템이 모듈을 평가하면 선언과 정의를 바탕으로 속성 집합이 만들어집니다.

가장 단순한 모듈은 아무 속성이나 받아 빈 속성 집합을 반환하는 함수입니다:

```{code-block} nix
:caption: options.nix
{ ... }:
{
}
```

값을 정의하려면 모듈 시스템이 먼저 어떤 값이 허용되는지 알아야 합니다. 이를 위해 어떤 속성을 설정하고 다른 곳에서 사용할 수 있는지 지정하는 *옵션*을 선언합니다.

## 옵션 선언하기

옵션은 최상위 `options` 속성 아래에 [`lib.mkOption`](https://nixos.org/manual/nixpkgs/stable/#function-library-lib.options.mkOption)으로 선언합니다.

```{literalinclude} options.nix
:language: nix
:caption: options.nix
```

:::{note}
`lib` 인수는 모듈 시스템이 자동으로 전달합니다. 이 인수 덕분에 각 모듈의 함수 본문에서 [Nixpkgs 라이브러리 함수](https://nixos.org/manual/nixpkgs/stable/#chap-functions)를 사용할 수 있습니다.

모듈 시스템이 모듈에 임의의 인수를 전달할 수 있으므로 생략 부호 `...`가 필요합니다.

:::

`lib.mkOption`에 전달하는 인수의 `type` 속성은 옵션에 어떤 값이 유효한지 지정합니다. [`lib.types`](https://nixos.org/manual/nixos/stable/#sec-option-types-basic) 아래에서 여러 타입을 사용할 수 있습니다.

여기서는 `str` 타입의 `name` 옵션을 선언했습니다: 값이 정의되면 모듈 시스템은 문자열을 기대합니다.

옵션을 선언했으니 이제 당연히 값을 지정하고 싶을 것입니다.

## 값 정의하기

옵션은 최상위 `config` 속성 아래에서 설정하거나 *정의*합니다:

```{literalinclude} config.nix
:language: nix
:caption: config.nix
```

옵션 선언에서는 문자열 타입의 `name` 옵션을 만들었습니다. 여기 옵션 정의에서는 바로 그 옵션을 문자열로 설정했습니다.

옵션 선언과 옵션 정의가 같은 파일에 있을 필요는 없습니다. 어떤 모듈이 최종 속성 집합에 기여할지는 모듈 시스템 평가를 구성할 때 지정합니다.

## 모듈 평가하기

모듈은 Nixpkgs 라이브러리의 [`lib.evalModules`](https://nixos.org/manual/nixpkgs/stable/#module-system-lib-evalModules)로 평가합니다. 이 함수는 속성 집합을 인수로 받으며, 그중 `modules` 속성은 병합하고 평가할 모듈의 목록입니다.

`evalModules`의 출력에는 평가된 모든 모듈에 대한 정보가 담기며, 최종 값은 `config` 속성에 나타납니다.

```{literalinclude} default.nix
:language: nix
:caption: default.nix
```

다음은 [`nix-instantiate --eval`](https://nix.dev/manual/nix/stable/command-ref/nix-instantiate)로 `default.nix` 파일을 파싱 및 평가하고 결과를 JSON으로 출력하는 헬퍼 스크립트입니다:

```{literalinclude} eval.bash
:language: bash
:caption: eval.bash
```

모든 정의(definition)에 대응하는 선언(declaration)이 있는 한 평가는 성공합니다. 선언되지 않은 옵션 정의가 있거나 정의된 값의 타입이 잘못된 경우, 모듈 시스템이 오류를 발생시킵니다.

스크립트(`./eval.bash`)를 실행하면 우리가 설정한 내용과 일치하는 출력이 표시될 것입니다:

```{code-block}
{
  "name": "Boaty McBoatface"
}
```
