@hivehub/rulebook 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +779 -654
- package/dist/cli/commands.d.ts +22 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +291 -8
- package/dist/cli/commands.js.map +1 -1
- package/dist/core/claude-mcp.d.ts +32 -0
- package/dist/core/claude-mcp.d.ts.map +1 -0
- package/dist/core/claude-mcp.js +92 -0
- package/dist/core/claude-mcp.js.map +1 -0
- package/dist/core/config-manager.d.ts.map +1 -1
- package/dist/core/config-manager.js +27 -6
- package/dist/core/config-manager.js.map +1 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +98 -49
- package/dist/core/generator.js.map +1 -1
- package/dist/core/migrator.d.ts +13 -0
- package/dist/core/migrator.d.ts.map +1 -1
- package/dist/core/migrator.js +76 -9
- package/dist/core/migrator.js.map +1 -1
- package/dist/core/openspec-migrator.d.ts +1 -1
- package/dist/core/openspec-migrator.d.ts.map +1 -1
- package/dist/core/openspec-migrator.js +14 -7
- package/dist/core/openspec-migrator.js.map +1 -1
- package/dist/core/workflow-generator.js +297 -176
- package/dist/core/workflow-generator.js.map +1 -1
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +255 -74
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/memory/hnsw-index.d.ts +63 -0
- package/dist/memory/hnsw-index.d.ts.map +1 -0
- package/dist/memory/hnsw-index.js +421 -0
- package/dist/memory/hnsw-index.js.map +1 -0
- package/dist/memory/memory-cache.d.ts +33 -0
- package/dist/memory/memory-cache.d.ts.map +1 -0
- package/dist/memory/memory-cache.js +85 -0
- package/dist/memory/memory-cache.js.map +1 -0
- package/dist/memory/memory-hooks.d.ts +42 -0
- package/dist/memory/memory-hooks.d.ts.map +1 -0
- package/dist/memory/memory-hooks.js +193 -0
- package/dist/memory/memory-hooks.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +55 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +209 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/memory-search.d.ts +42 -0
- package/dist/memory/memory-search.d.ts.map +1 -0
- package/dist/memory/memory-search.js +166 -0
- package/dist/memory/memory-search.js.map +1 -0
- package/dist/memory/memory-store.d.ts +59 -0
- package/dist/memory/memory-store.d.ts.map +1 -0
- package/dist/memory/memory-store.js +394 -0
- package/dist/memory/memory-store.js.map +1 -0
- package/dist/memory/memory-types.d.ts +69 -0
- package/dist/memory/memory-types.d.ts.map +1 -0
- package/dist/memory/memory-types.js +7 -0
- package/dist/memory/memory-types.js.map +1 -0
- package/dist/memory/memory-vectorizer.d.ts +29 -0
- package/dist/memory/memory-vectorizer.d.ts.map +1 -0
- package/dist/memory/memory-vectorizer.js +104 -0
- package/dist/memory/memory-vectorizer.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +107 -106
- package/templates/cli/CLAUDE_CODE.md +114 -13
- package/templates/commands/rulebook-memory-save.md +48 -0
- package/templates/commands/rulebook-memory-search.md +47 -0
- package/templates/commands/rulebook-task-apply.md +2 -2
- package/templates/commands/rulebook-task-archive.md +2 -2
- package/templates/commands/rulebook-task-create.md +2 -2
- package/templates/commands/rulebook-task-list.md +2 -2
- package/templates/commands/rulebook-task-show.md +2 -2
- package/templates/commands/rulebook-task-validate.md +2 -2
- package/templates/git/CI_CD_PATTERNS.md +4 -4
- package/templates/git/GITHUB_ACTIONS.md +3 -3
- package/templates/git/GITLAB_CI.md +4 -4
- package/templates/git/SECRETS_MANAGEMENT.md +4 -4
- package/templates/hooks/COMMIT_MSG.md +4 -4
- package/templates/hooks/POST_CHECKOUT.md +3 -3
- package/templates/hooks/PREPARE_COMMIT_MSG.md +3 -3
- package/templates/hooks/PRE_COMMIT.md +4 -4
- package/templates/hooks/PRE_PUSH.md +4 -4
- package/templates/modules/MEMORY.md +63 -0
- package/templates/skills/cli/aider/SKILL.md +59 -0
- package/templates/skills/cli/amazon-q/SKILL.md +35 -0
- package/templates/skills/cli/auggie/SKILL.md +42 -0
- package/templates/skills/cli/claude/SKILL.md +42 -0
- package/templates/skills/cli/claude-code/SKILL.md +146 -0
- package/templates/skills/cli/cline/SKILL.md +42 -0
- package/templates/skills/cli/codebuddy/SKILL.md +30 -0
- package/templates/skills/cli/codeium/SKILL.md +30 -0
- package/templates/skills/cli/codex/SKILL.md +31 -0
- package/templates/skills/cli/continue/SKILL.md +44 -0
- package/templates/skills/cli/cursor-cli/SKILL.md +38 -0
- package/templates/skills/cli/factory/SKILL.md +28 -0
- package/templates/skills/cli/gemini/SKILL.md +45 -0
- package/templates/skills/cli/kilocode/SKILL.md +28 -0
- package/templates/skills/cli/opencode/SKILL.md +28 -0
- package/templates/skills/core/agent-automation/SKILL.md +194 -0
- package/templates/skills/core/dag/SKILL.md +314 -0
- package/templates/skills/core/documentation-rules/SKILL.md +47 -0
- package/templates/skills/core/quality-enforcement/SKILL.md +78 -0
- package/templates/skills/frameworks/angular/SKILL.md +46 -0
- package/templates/skills/frameworks/django/SKILL.md +93 -0
- package/templates/skills/frameworks/electron/SKILL.md +157 -0
- package/templates/skills/frameworks/flask/SKILL.md +48 -0
- package/templates/skills/frameworks/flutter/SKILL.md +65 -0
- package/templates/skills/frameworks/jquery/SKILL.md +42 -0
- package/templates/skills/frameworks/laravel/SKILL.md +48 -0
- package/templates/skills/frameworks/nestjs/SKILL.md +53 -0
- package/templates/skills/frameworks/nextjs/SKILL.md +137 -0
- package/templates/skills/frameworks/nuxt/SKILL.md +50 -0
- package/templates/skills/frameworks/rails/SKILL.md +76 -0
- package/templates/skills/frameworks/react/SKILL.md +48 -0
- package/templates/skills/frameworks/react-native/SKILL.md +57 -0
- package/templates/skills/frameworks/spring/SKILL.md +49 -0
- package/templates/skills/frameworks/symfony/SKILL.md +46 -0
- package/templates/skills/frameworks/vue/SKILL.md +46 -0
- package/templates/skills/frameworks/zend/SKILL.md +45 -0
- package/templates/skills/ides/copilot/SKILL.md +47 -0
- package/templates/skills/ides/cursor/SKILL.md +53 -0
- package/templates/skills/ides/jetbrains-ai/SKILL.md +45 -0
- package/templates/skills/ides/replit/SKILL.md +46 -0
- package/templates/skills/ides/tabnine/SKILL.md +39 -0
- package/templates/skills/ides/vscode/SKILL.md +50 -0
- package/templates/skills/ides/windsurf/SKILL.md +46 -0
- package/templates/skills/ides/zed/SKILL.md +42 -0
- package/templates/skills/languages/ada/SKILL.md +68 -0
- package/templates/skills/languages/c/SKILL.md +343 -0
- package/templates/skills/languages/cpp/SKILL.md +753 -0
- package/templates/skills/languages/csharp/SKILL.md +427 -0
- package/templates/skills/languages/dart/SKILL.md +342 -0
- package/templates/skills/languages/elixir/SKILL.md +464 -0
- package/templates/skills/languages/erlang/SKILL.md +371 -0
- package/templates/skills/languages/go/SKILL.md +655 -0
- package/templates/skills/languages/haskell/SKILL.md +187 -0
- package/templates/skills/languages/java/SKILL.md +617 -0
- package/templates/skills/languages/javascript/SKILL.md +641 -0
- package/templates/skills/languages/julia/SKILL.md +107 -0
- package/templates/skills/languages/kotlin/SKILL.md +521 -0
- package/templates/skills/languages/lisp/SKILL.md +110 -0
- package/templates/skills/languages/lua/SKILL.md +84 -0
- package/templates/skills/languages/objectivec/SKILL.md +100 -0
- package/templates/skills/languages/php/SKILL.md +426 -0
- package/templates/skills/languages/python/SKILL.md +692 -0
- package/templates/skills/languages/r/SKILL.md +360 -0
- package/templates/skills/languages/ruby/SKILL.md +431 -0
- package/templates/skills/languages/rust/SKILL.md +487 -0
- package/templates/skills/languages/sas/SKILL.md +83 -0
- package/templates/skills/languages/scala/SKILL.md +358 -0
- package/templates/skills/languages/solidity/SKILL.md +590 -0
- package/templates/skills/languages/sql/SKILL.md +147 -0
- package/templates/skills/languages/swift/SKILL.md +476 -0
- package/templates/skills/languages/zig/SKILL.md +275 -0
- package/templates/skills/modules/atlassian/SKILL.md +265 -0
- package/templates/skills/modules/context7/SKILL.md +64 -0
- package/templates/skills/modules/figma/SKILL.md +277 -0
- package/templates/skills/modules/github-mcp/SKILL.md +74 -0
- package/templates/skills/modules/grafana/SKILL.md +338 -0
- package/templates/skills/modules/memory/SKILL.md +73 -0
- package/templates/skills/modules/notion/SKILL.md +257 -0
- package/templates/skills/modules/playwright/SKILL.md +100 -0
- package/templates/skills/modules/rulebook-mcp/SKILL.md +166 -0
- package/templates/skills/modules/serena/SKILL.md +347 -0
- package/templates/skills/modules/supabase/SKILL.md +233 -0
- package/templates/skills/modules/synap/SKILL.md +79 -0
- package/templates/skills/modules/vectorizer/SKILL.md +73 -0
- package/templates/skills/services/azure-blob/SKILL.md +194 -0
- package/templates/skills/services/cassandra/SKILL.md +249 -0
- package/templates/skills/services/dynamodb/SKILL.md +318 -0
- package/templates/skills/services/elasticsearch/SKILL.md +357 -0
- package/templates/skills/services/gcs/SKILL.md +188 -0
- package/templates/skills/services/influxdb/SKILL.md +275 -0
- package/templates/skills/services/kafka/SKILL.md +351 -0
- package/templates/skills/services/mariadb/SKILL.md +193 -0
- package/templates/skills/services/memcached/SKILL.md +252 -0
- package/templates/skills/services/minio/SKILL.md +211 -0
- package/templates/skills/services/mongodb/SKILL.md +278 -0
- package/templates/skills/services/mysql/SKILL.md +368 -0
- package/templates/skills/services/neo4j/SKILL.md +257 -0
- package/templates/skills/services/oracle/SKILL.md +300 -0
- package/templates/skills/services/postgresql/SKILL.md +336 -0
- package/templates/skills/services/rabbitmq/SKILL.md +296 -0
- package/templates/skills/services/redis/SKILL.md +302 -0
- package/templates/skills/services/s3/SKILL.md +308 -0
- package/templates/skills/services/sqlite/SKILL.md +304 -0
- package/templates/skills/services/sqlserver/SKILL.md +304 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Erlang"
|
|
3
|
+
description: "Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow)."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
category: "languages"
|
|
6
|
+
author: "Rulebook"
|
|
7
|
+
tags: ["languages", "language"]
|
|
8
|
+
dependencies: []
|
|
9
|
+
conflicts: []
|
|
10
|
+
---
|
|
11
|
+
<!-- ERLANG:START -->
|
|
12
|
+
# Erlang Project Rules
|
|
13
|
+
|
|
14
|
+
## Agent Automation Commands
|
|
15
|
+
|
|
16
|
+
**CRITICAL**: Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Complete quality check sequence:
|
|
20
|
+
rebar3 format --verify # Format check
|
|
21
|
+
rebar3 dialyzer # Type analysis
|
|
22
|
+
rebar3 eunit # Unit tests
|
|
23
|
+
rebar3 ct # Common Test
|
|
24
|
+
rebar3 cover # Coverage check
|
|
25
|
+
rebar3 compile # Build verification
|
|
26
|
+
|
|
27
|
+
# Security audit:
|
|
28
|
+
rebar3 tree # Dependency tree
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Erlang Configuration
|
|
32
|
+
|
|
33
|
+
**CRITICAL**: Use Erlang/OTP 26+ with rebar3 and proper testing.
|
|
34
|
+
|
|
35
|
+
- **Version**: Erlang/OTP 26+
|
|
36
|
+
- **Recommended**: Erlang/OTP 27+
|
|
37
|
+
- **Build Tool**: rebar3
|
|
38
|
+
- **Testing**: EUnit, Common Test, PropEr
|
|
39
|
+
- **Linter**: Elvis
|
|
40
|
+
- **Dialyzer**: Type analysis
|
|
41
|
+
- **Documentation**: EDoc
|
|
42
|
+
|
|
43
|
+
### rebar.config Requirements
|
|
44
|
+
|
|
45
|
+
```erlang
|
|
46
|
+
{erl_opts, [
|
|
47
|
+
debug_info,
|
|
48
|
+
warnings_as_errors,
|
|
49
|
+
warn_export_all,
|
|
50
|
+
warn_unused_import,
|
|
51
|
+
warn_untyped_record
|
|
52
|
+
]}.
|
|
53
|
+
|
|
54
|
+
{deps, [
|
|
55
|
+
{jsx, "3.1.0"}
|
|
56
|
+
]}.
|
|
57
|
+
|
|
58
|
+
{plugins, [
|
|
59
|
+
rebar3_hex,
|
|
60
|
+
rebar3_ex_doc,
|
|
61
|
+
rebar3_proper,
|
|
62
|
+
rebar3_lint
|
|
63
|
+
]}.
|
|
64
|
+
|
|
65
|
+
{profiles, [
|
|
66
|
+
{test, [
|
|
67
|
+
{erl_opts, [debug_info, export_all, nowarn_export_all]},
|
|
68
|
+
{deps, [
|
|
69
|
+
{meck, "0.9.2"},
|
|
70
|
+
{proper, "1.4.0"}
|
|
71
|
+
]}
|
|
72
|
+
]},
|
|
73
|
+
{prod, [
|
|
74
|
+
{erl_opts, [no_debug_info, warnings_as_errors]},
|
|
75
|
+
{relx, [
|
|
76
|
+
{dev_mode, false},
|
|
77
|
+
{include_erts, true},
|
|
78
|
+
{include_src, false}
|
|
79
|
+
]}
|
|
80
|
+
]}
|
|
81
|
+
]}.
|
|
82
|
+
|
|
83
|
+
{cover_enabled, true}.
|
|
84
|
+
{cover_opts, [verbose]}.
|
|
85
|
+
|
|
86
|
+
{dialyzer, [
|
|
87
|
+
{warnings, [
|
|
88
|
+
error_handling,
|
|
89
|
+
underspecs,
|
|
90
|
+
unmatched_returns
|
|
91
|
+
]},
|
|
92
|
+
{get_warnings, true},
|
|
93
|
+
{plt_apps, top_level_deps},
|
|
94
|
+
{plt_extra_apps, []},
|
|
95
|
+
{plt_location, local},
|
|
96
|
+
{base_plt_apps, [erts, kernel, stdlib]},
|
|
97
|
+
{base_plt_location, global}
|
|
98
|
+
]}.
|
|
99
|
+
|
|
100
|
+
{xref_checks, [
|
|
101
|
+
undefined_function_calls,
|
|
102
|
+
undefined_functions,
|
|
103
|
+
locals_not_used,
|
|
104
|
+
deprecated_function_calls,
|
|
105
|
+
deprecated_functions
|
|
106
|
+
]}.
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Code Quality Standards
|
|
110
|
+
|
|
111
|
+
### Mandatory Quality Checks
|
|
112
|
+
|
|
113
|
+
**CRITICAL**: After implementing ANY feature, you MUST run these commands in order.
|
|
114
|
+
|
|
115
|
+
**IMPORTANT**: These commands MUST match your GitHub Actions workflows to prevent CI/CD failures!
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Pre-Commit Checklist (MUST match .github/workflows/*.yml)
|
|
119
|
+
|
|
120
|
+
# 1. Format check (matches workflow)
|
|
121
|
+
rebar3 as test fmt --check
|
|
122
|
+
|
|
123
|
+
# 2. Lint (matches workflow)
|
|
124
|
+
rebar3 as test lint
|
|
125
|
+
|
|
126
|
+
# 3. Compile (matches workflow)
|
|
127
|
+
rebar3 compile
|
|
128
|
+
|
|
129
|
+
# 4. Dialyzer (type analysis - matches workflow)
|
|
130
|
+
rebar3 dialyzer
|
|
131
|
+
|
|
132
|
+
# 5. Run EUnit tests (MUST pass 100% - matches workflow)
|
|
133
|
+
rebar3 eunit
|
|
134
|
+
|
|
135
|
+
# 6. Run Common Test (matches workflow)
|
|
136
|
+
rebar3 ct
|
|
137
|
+
|
|
138
|
+
# 7. Run PropEr properties (matches workflow)
|
|
139
|
+
rebar3 proper
|
|
140
|
+
|
|
141
|
+
# 8. Coverage (MUST meet threshold - matches workflow)
|
|
142
|
+
rebar3 cover
|
|
143
|
+
|
|
144
|
+
# 9. Cross-reference check (matches workflow)
|
|
145
|
+
rebar3 xref
|
|
146
|
+
|
|
147
|
+
# If ANY fails: ❌ DO NOT COMMIT - Fix first!
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**If ANY of these fail, you MUST fix the issues before committing.**
|
|
151
|
+
|
|
152
|
+
**Why This Matters:**
|
|
153
|
+
- Running different commands locally than in CI causes OTP release failures
|
|
154
|
+
- Dialyzer errors caught in CI but not locally = type safety issues
|
|
155
|
+
- Example: Skipping Dialyzer locally = CI catches type discrepancies
|
|
156
|
+
- Example: Missing xref check = undefined function calls in production
|
|
157
|
+
- Example: Not running PropEr = property violations in production
|
|
158
|
+
|
|
159
|
+
### Testing
|
|
160
|
+
|
|
161
|
+
- **EUnit**: Unit testing framework
|
|
162
|
+
- **Common Test**: Integration and system tests
|
|
163
|
+
- **PropEr**: Property-based testing
|
|
164
|
+
- **Location**: `test/` directory
|
|
165
|
+
|
|
166
|
+
Example EUnit test:
|
|
167
|
+
```erlang
|
|
168
|
+
-module(data_processor_tests).
|
|
169
|
+
-include_lib("eunit/include/eunit.hrl").
|
|
170
|
+
|
|
171
|
+
process_valid_input_test() ->
|
|
172
|
+
Input = [1, 2, 3, 4, 5],
|
|
173
|
+
Result = data_processor:process(Input, 0.5),
|
|
174
|
+
?assert(length(Result) > 0).
|
|
175
|
+
|
|
176
|
+
process_empty_input_test() ->
|
|
177
|
+
Result = data_processor:process([], 0.5),
|
|
178
|
+
?assertEqual([], Result).
|
|
179
|
+
|
|
180
|
+
process_invalid_threshold_test() ->
|
|
181
|
+
?assertError(badarg, data_processor:process([1, 2, 3], -1)).
|
|
182
|
+
|
|
183
|
+
process_with_options_test() ->
|
|
184
|
+
Options = #{threshold => 0.5, verbose => true},
|
|
185
|
+
Result = data_processor:process([1, 2, 3], Options),
|
|
186
|
+
?assert(is_list(Result)).
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Example Common Test:
|
|
190
|
+
```erlang
|
|
191
|
+
-module(integration_SUITE).
|
|
192
|
+
-include_lib("common_test/include/ct.hrl").
|
|
193
|
+
|
|
194
|
+
-export([all/0, init_per_suite/1, end_per_suite/1]).
|
|
195
|
+
-export([test_basic_workflow/1, test_error_handling/1]).
|
|
196
|
+
|
|
197
|
+
all() ->
|
|
198
|
+
[test_basic_workflow, test_error_handling].
|
|
199
|
+
|
|
200
|
+
init_per_suite(Config) ->
|
|
201
|
+
application:ensure_all_started(your_app),
|
|
202
|
+
Config.
|
|
203
|
+
|
|
204
|
+
end_per_suite(_Config) ->
|
|
205
|
+
application:stop(your_app),
|
|
206
|
+
ok.
|
|
207
|
+
|
|
208
|
+
test_basic_workflow(_Config) ->
|
|
209
|
+
{ok, Pid} = data_processor:start_link(),
|
|
210
|
+
ok = data_processor:process(Pid, [1, 2, 3]),
|
|
211
|
+
{ok, Result} = data_processor:get_result(Pid),
|
|
212
|
+
true = length(Result) > 0,
|
|
213
|
+
ok = data_processor:stop(Pid).
|
|
214
|
+
|
|
215
|
+
test_error_handling(_Config) ->
|
|
216
|
+
{ok, Pid} = data_processor:start_link(),
|
|
217
|
+
{error, badarg} = data_processor:process(Pid, invalid_input),
|
|
218
|
+
ok = data_processor:stop(Pid).
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Example PropEr property:
|
|
222
|
+
```erlang
|
|
223
|
+
-module(prop_data_processor).
|
|
224
|
+
-include_lib("proper/include/proper.hrl").
|
|
225
|
+
-include_lib("eunit/include/eunit.hrl").
|
|
226
|
+
|
|
227
|
+
prop_process_preserves_length() ->
|
|
228
|
+
?FORALL(List, list(integer()),
|
|
229
|
+
begin
|
|
230
|
+
Result = data_processor:process(List, 0.5),
|
|
231
|
+
length(Result) =< length(List)
|
|
232
|
+
end).
|
|
233
|
+
|
|
234
|
+
prop_process_filters_correctly() ->
|
|
235
|
+
?FORALL({List, Threshold}, {list(number()), number()},
|
|
236
|
+
begin
|
|
237
|
+
Result = data_processor:process(List, Threshold),
|
|
238
|
+
lists:all(fun(X) -> X > Threshold end, Result)
|
|
239
|
+
end).
|
|
240
|
+
|
|
241
|
+
% Run properties
|
|
242
|
+
process_properties_test() ->
|
|
243
|
+
?assert(proper:quickcheck(prop_process_preserves_length(), 100)),
|
|
244
|
+
?assert(proper:quickcheck(prop_process_filters_correctly(), 100)).
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## OTP Patterns
|
|
248
|
+
|
|
249
|
+
**CRITICAL**: Follow OTP principles for robust systems.
|
|
250
|
+
|
|
251
|
+
```erlang
|
|
252
|
+
-module(data_server).
|
|
253
|
+
-behaviour(gen_server).
|
|
254
|
+
|
|
255
|
+
%% API
|
|
256
|
+
-export([start_link/0, process/2, stop/1]).
|
|
257
|
+
|
|
258
|
+
%% gen_server callbacks
|
|
259
|
+
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
|
|
260
|
+
|
|
261
|
+
-record(state, {
|
|
262
|
+
threshold :: float(),
|
|
263
|
+
cache :: map()
|
|
264
|
+
}).
|
|
265
|
+
|
|
266
|
+
%%% API
|
|
267
|
+
|
|
268
|
+
start_link() ->
|
|
269
|
+
gen_server:start_link(?MODULE, [], []).
|
|
270
|
+
|
|
271
|
+
process(Pid, Data) ->
|
|
272
|
+
gen_server:call(Pid, {process, Data}).
|
|
273
|
+
|
|
274
|
+
stop(Pid) ->
|
|
275
|
+
gen_server:stop(Pid).
|
|
276
|
+
|
|
277
|
+
%%% gen_server callbacks
|
|
278
|
+
|
|
279
|
+
init([]) ->
|
|
280
|
+
{ok, #state{threshold = 0.5, cache = #{}}}.
|
|
281
|
+
|
|
282
|
+
handle_call({process, Data}, _From, State) ->
|
|
283
|
+
Result = filter_data(Data, State#state.threshold),
|
|
284
|
+
NewCache = maps:put(Data, Result, State#state.cache),
|
|
285
|
+
{reply, {ok, Result}, State#state{cache = NewCache}};
|
|
286
|
+
handle_call(_Request, _From, State) ->
|
|
287
|
+
{reply, {error, unknown_request}, State}.
|
|
288
|
+
|
|
289
|
+
handle_cast(_Msg, State) ->
|
|
290
|
+
{noreply, State}.
|
|
291
|
+
|
|
292
|
+
handle_info(_Info, State) ->
|
|
293
|
+
{noreply, State}.
|
|
294
|
+
|
|
295
|
+
terminate(_Reason, _State) ->
|
|
296
|
+
ok.
|
|
297
|
+
|
|
298
|
+
%%% Internal functions
|
|
299
|
+
|
|
300
|
+
filter_data(Data, Threshold) ->
|
|
301
|
+
[X || X <- Data, X > Threshold].
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Best Practices
|
|
305
|
+
|
|
306
|
+
### DO's ✅
|
|
307
|
+
|
|
308
|
+
- **USE** OTP behaviors (gen_server, gen_statem, supervisor)
|
|
309
|
+
- **HANDLE** all error cases with pattern matching
|
|
310
|
+
- **USE** typespecs for all exported functions
|
|
311
|
+
- **TEST** with PropEr for property-based testing
|
|
312
|
+
- **USE** supervisor trees for fault tolerance
|
|
313
|
+
- **VALIDATE** inputs in public APIs
|
|
314
|
+
- **DOCUMENT** with EDoc
|
|
315
|
+
|
|
316
|
+
### DON'Ts ❌
|
|
317
|
+
|
|
318
|
+
- **NEVER** ignore Dialyzer warnings
|
|
319
|
+
- **NEVER** use catch-all patterns without logging
|
|
320
|
+
- **NEVER** create processes without supervision
|
|
321
|
+
- **NEVER** skip xref checks
|
|
322
|
+
- **NEVER** use deprecated functions
|
|
323
|
+
- **NEVER** ignore test failures
|
|
324
|
+
- **NEVER** deploy without Dialyzer clean
|
|
325
|
+
|
|
326
|
+
Example with typespecs:
|
|
327
|
+
```erlang
|
|
328
|
+
-module(calculator).
|
|
329
|
+
-export([add/2, divide/2]).
|
|
330
|
+
|
|
331
|
+
-spec add(number(), number()) -> number().
|
|
332
|
+
add(A, B) -> A + B.
|
|
333
|
+
|
|
334
|
+
-spec divide(number(), number()) -> {ok, float()} | {error, divide_by_zero}.
|
|
335
|
+
divide(_A, 0) -> {error, divide_by_zero};
|
|
336
|
+
divide(A, B) -> {ok, A / B}.
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## CI/CD Requirements
|
|
340
|
+
|
|
341
|
+
Must include GitHub Actions workflows:
|
|
342
|
+
|
|
343
|
+
1. **Testing** (`erlang-test.yml`):
|
|
344
|
+
- OTP versions: 26, 27
|
|
345
|
+
- Run EUnit, CT, PropEr
|
|
346
|
+
- Coverage reporting
|
|
347
|
+
|
|
348
|
+
2. **Linting** (`erlang-lint.yml`):
|
|
349
|
+
- Elvis linting
|
|
350
|
+
- Dialyzer type checking
|
|
351
|
+
- xref verification
|
|
352
|
+
|
|
353
|
+
3. **Build** (`erlang-build.yml`):
|
|
354
|
+
- Create OTP release
|
|
355
|
+
- Verify all applications start
|
|
356
|
+
|
|
357
|
+
## Publishing to Hex.pm
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# 1. Update version in src/your_app.app.src
|
|
361
|
+
# 2. Run all quality checks
|
|
362
|
+
rebar3 dialyzer
|
|
363
|
+
rebar3 eunit
|
|
364
|
+
rebar3 ct
|
|
365
|
+
|
|
366
|
+
# 3. Publish
|
|
367
|
+
rebar3 hex publish
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
<!-- ERLANG:END -->
|
|
371
|
+
|