# Tool

## Property

```typescript
const tool = {
    install: 'function',
    handler: 'function', // required
    request: 'array',
    response: 'string',
}
```

### Install

第一次呼叫時執行，只會執行一次。

{% hint style="info" %}
Install只允許同步執行，若執意使用非同步請求可以參閱[Loader](/the-instance/utils.md#loader)。
{% endhint %}

```javascript
const tool = {
    install({ packhouse, store, include, utils, group }) { ... }
}
```

#### Packhouse

實例化的Packhouse對象，主要在於運用[Plugin](/the-instance/plugin.md)。

#### Store

變數的容器，能在`handler`中被獲取。

```javascript
const tool = {
    install({ store }) {
        store.demo = 5
    },
    handler(self) {
        console.log(self.store.demo) // 5
    }
}
```

#### Include

引用其他的Tool必須經過`include`，該接口也能引用[其他Group](/the-instance/group.md#mergers)或[Line](/the-instance/group/line.md)。

```javascript
const group = {
   tools: {
      sum: {
         handler: (self, v1, v2) => self.success(v1 + v2)
      },
      double: {
         install({ include }) {
            // 參數一是引用名，第二個參數是tool name。
            include('sum').tool('sum')
         },
         handler(self, v1) {
            self.tool('sum')
                .action(v1, v1, (error, result) => {
                   self.success(result)
                })
         }
      }
   }
}
```

#### Group

與Group交換資料的管道，也意味著能與外部的參數進行溝通：

```javascript
const group = {
   install(group, options) {
      group.locale = options.locale
   },
   tools: {
      where: {
         install({ store, group }) {
            store.locale = group.locale
         },
         handler(self) {
            self.success(self.store.locale)
         }
      }
   }
}

packhouse.addGroup('locale', () => {
   return {
      data: group,
      options: {
         locale: '台灣'
      }
   }
})

packhouse.tool('locale/where').action((error, result) => {
   console.log(result) // '台灣'
})
```

#### Utils

可以使用Packhouse提供的工具組，詳情參照[Utils](/the-instance/utils.md)。

## Handler

Tool被呼叫時的主執行續。

{% hint style="info" %}
如果整個`handler`的過程是同步的，那`action`的執行是完全同步的，但建議把所有的行為視為非同步。
{% endhint %}

```javascript
const tool = {
    handler(self, ...args) {
        self.success()
    }
}
```

### Self

主要的流程控制單元，固定在第一個參數上，以下是它的Property：

#### success

回傳成功結果

#### error

回傳錯誤結果

#### casting

回傳與驗證參數，詳情請參閱[Mold Casting](/the-instance/group/mold.md#casting)。

#### line

引用`include`的[Line](/the-instance/group/line.md)。

#### tool

引用`include`的Tool。

#### assess

驗證第一個參數是否為null或undefined，若不是則回傳第一個參數，若成立則回傳第二個參數。

> assess可以接受一個Callback，當第二個參數成立時可觸發並回傳該方法的結果。

```javascript
const group = {
   tools: {
      sum: {
         request: ['number', 'number'],
         handler: (self, v1, v2) => self.success(v1 + v2)
      },
      doubleAndToInt: {
         install({ include }) {
            include('sum').tool('sum')
         },
         handler(self, v1) {
            self.tool('sum')
                .action(v1, v1, self.assess(result => parseInt(result)))
         }
      }
   }
}

// ... 省略註冊行為

packhouse.tool('math/doubleAndToInt').action(10.2, (error, result) => {
   console.log(result) // 20
})

packhouse.tool('math/doubleAndToInt').action('10.2', (error, result) => {
   console.log(error != null) // true
})
```

### Lazy First

在Cloud Function的型態下，我們只要專注在單一功能上，意味著每次執行只要針對目的`require`所需的模塊即可。

{% hint style="info" %}
並不建議將`require`的行為建立在`install`的行為內，除了可讀性差之外也可能造成`this`指向錯誤或影響單元測試等行為。
{% endhint %}

```javascript
// 這是個糟糕的例子😢
let moment = require('moment')
const badTool = {
    handler(self) {
        self.success(moment())
    }
}
```

```javascript
// 這是個優良案例 🤣
const tool = {
    handler(self) {
        let moment = require('moment')
        self.success(moment())
    }
}
```

### Async

Install必須是同步的，但Handler允許非同步運作。

```javascript
const tool = {
    handler: async self => setTimeout(self.success, 100)
}
```

## Request & Response

指定參數與回傳值的型態與驗證對象，比對方法詳情請參照[Mold](/the-instance/group/mold.md)。

```javascript
const tools = {
    sum: {
        request: ['number', 'number'],
        response: 'number',
        handler(self, v1, v2) {
            self.success(v1 + v2)
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://packhouse-doc.metalsheep.com/the-instance/group/tool.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
