Skip to content

Commit 7084eae

Browse files
committed
refactor: simplify resolver config by removing redundant function name
Remove function name from resolver tuple since it's implicit from behaviour. ## Changes **Before**: `{Module, :resolve, [context]}` **After**: `{Module, [context]}` ## Rationale Since ModuleResolver behaviour defines `resolve/3`, the function name is redundant and can be inferred. This makes the configuration cleaner. ## Updated API - Type: `resolver()` instead of `mfa()` - Helper: `new/2` instead of `to_mfa/2` - Caller: `resolve/3` instead of `call_mfa/3` ## Example ```elixir # Initialize context = ModuleResolver.Default.init(repo: MyApp.Repo) resolver = ModuleResolver.new(ModuleResolver.Default, context) # Returns: {ModuleResolver.Default, [context]} # Use in enactment {:ok, module} = ModuleResolver.resolve(resolver, module_ref, runtime_info) # Internally: apply(ModuleResolver.Default, :resolve, [ref, context, info]) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f7a844f commit 7084eae

1 file changed

Lines changed: 37 additions & 30 deletions

File tree

docs/module_resolver_mfa_based.md

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
┌──────────────────────────────────────────┐
77
│ Application Initialization │
88
│ - Create resolver context │
9-
│ - Form MFA: {Mod, :resolve, [context]} │
9+
│ - Form resolver: {Mod, [context]}
1010
└──────────────┬───────────────────────────┘
1111
1212
1313
┌──────────────────────────────────────────┐
1414
│ Enactment Initialization │
15-
│ - Receives resolver_mfa
15+
│ - Receives resolver config
1616
│ - Stores in enactment state │
1717
└──────────────┬───────────────────────────┘
1818
@@ -100,44 +100,44 @@ defmodule ColouredFlow.Runtime.ModuleResolver do
100100
# ... behaviour definition ...
101101

102102
@typedoc """
103-
Module resolver in MFA form.
103+
Module resolver configuration.
104104
105105
The tuple contains:
106106
- module: Module implementing ModuleResolver behaviour
107-
- function: Always :resolve
108107
- args: List containing [context] (pre-initialized)
109108
110-
When calling: apply(module, :resolve, [module_ref, context, runtime_info])
109+
Since the behaviour defines resolve/3, the function name is implicit.
110+
When calling: apply(module, :resolve, [module_ref] ++ args ++ [runtime_info])
111111
"""
112-
@type mfa() :: {module(), :resolve, [context()]}
112+
@type resolver() :: {module(), [context()]}
113113

114114
@doc """
115-
Helper to create MFA from resolver module and context.
115+
Helper to create resolver configuration from module and context.
116116
117117
## Examples
118118
119119
context = MyResolver.init(repo: MyApp.Repo)
120-
mfa = ModuleResolver.to_mfa(MyResolver, context)
121-
# Returns: {MyResolver, :resolve, [context]}
120+
resolver = ModuleResolver.new(MyResolver, context)
121+
# Returns: {MyResolver, [context]}
122122
"""
123-
@spec to_mfa(module(), context()) :: mfa()
124-
def to_mfa(resolver_module, context) when is_atom(resolver_module) do
125-
{resolver_module, :resolve, [context]}
123+
@spec new(module(), context()) :: resolver()
124+
def new(resolver_module, context) when is_atom(resolver_module) do
125+
{resolver_module, [context]}
126126
end
127127

128128
@doc """
129-
Helper to call MFA with module reference and runtime info.
129+
Call resolver with module reference and runtime info.
130130
131131
## Examples
132132
133-
mfa = {MyResolver, :resolve, [context]}
133+
resolver = {MyResolver, [context]}
134134
runtime_info = %{enactment_id: 123}
135-
{:ok, module} = ModuleResolver.call_mfa(mfa, module_ref, runtime_info)
135+
{:ok, module} = ModuleResolver.resolve(resolver, module_ref, runtime_info)
136136
"""
137-
@spec call_mfa(mfa(), module_ref(), runtime_info()) ::
137+
@spec resolve(resolver(), module_ref(), runtime_info()) ::
138138
{:ok, Module.t()} | {:error, term()}
139-
def call_mfa({module, :resolve, [context]}, module_ref, runtime_info) do
140-
apply(module, :resolve, [module_ref, context, runtime_info])
139+
def resolve({resolver_module, [context]}, module_ref, runtime_info) do
140+
apply(resolver_module, :resolve, [module_ref, context, runtime_info])
141141
end
142142
end
143143
```
@@ -305,12 +305,12 @@ end
305305

306306
# 1. Application level: Initialize resolver
307307
resolver_context = ModuleResolver.Default.init(repo: MyApp.Repo)
308-
resolver_mfa = ModuleResolver.to_mfa(ModuleResolver.Default, resolver_context)
308+
resolver = ModuleResolver.new(ModuleResolver.Default, resolver_context)
309309

310310
# 2. Pass to enactment
311311
{:ok, enactment_pid} = Enactment.start_link(
312312
cpnet: cpnet,
313-
resolver: resolver_mfa,
313+
resolver: resolver,
314314
# ... other options
315315
)
316316

@@ -319,7 +319,7 @@ defmodule ColouredFlow.Runner.Enactment do
319319
def init(opts) do
320320
state = %{
321321
cpnet: opts[:cpnet],
322-
resolver_mfa: opts[:resolver],
322+
resolver: opts[:resolver],
323323
enactment_id: generate_id(),
324324
# ...
325325
}
@@ -334,7 +334,7 @@ defmodule ColouredFlow.Runner.Enactment do
334334
parent_transition: transition.name
335335
}
336336

337-
case ModuleResolver.call_mfa(state.resolver_mfa, transition.subst, runtime_info) do
337+
case ModuleResolver.resolve(state.resolver, transition.subst, runtime_info) do
338338
{:ok, module} ->
339339
# Use the resolved module
340340
execute_module(module, ...)
@@ -359,10 +359,10 @@ defmodule MyApp.Application do
359359
def start(_type, _args) do
360360
# Initialize resolver
361361
resolver_context = ModuleResolver.Default.init(repo: MyApp.Repo)
362-
resolver_mfa = ModuleResolver.to_mfa(ModuleResolver.Default, resolver_context)
362+
resolver = ModuleResolver.new(ModuleResolver.Default, resolver_context)
363363

364364
# Store in application env or pass to supervisor
365-
Application.put_env(:my_app, :module_resolver, resolver_mfa)
365+
Application.put_env(:my_app, :module_resolver, resolver)
366366

367367
# Start supervisors...
368368
end
@@ -388,15 +388,21 @@ cpnet = %ColouredPetriNet{
388388
}
389389

390390
# 3. Start enactment with resolver
391-
resolver_mfa = Application.get_env(:my_app, :module_resolver)
391+
resolver = Application.get_env(:my_app, :module_resolver)
392392

393393
{:ok, enactment_pid} = Enactment.start_link(
394394
cpnet: cpnet,
395-
resolver: resolver_mfa,
395+
resolver: resolver,
396396
initial_marking: [...]
397397
)
398398

399399
# 4. When transition fires, enactment calls:
400+
# ModuleResolver.resolve(
401+
# {ModuleResolver.Default, [resolver_context]},
402+
# {:module_ref, flow_id: 123, port_specs: [...]},
403+
# %{enactment_id: "abc123", parent_transition: "authenticate"}
404+
# )
405+
# Which internally does:
400406
# apply(ModuleResolver.Default, :resolve, [
401407
# {:module_ref, flow_id: 123, port_specs: [...]},
402408
# resolver_context,
@@ -412,10 +418,11 @@ resolver_mfa = Application.get_env(:my_app, :module_resolver)
412418
4. **Testable**: Easy to mock MFA in tests
413419
5. **Flexible**: Can use different resolvers for different enactments
414420

415-
## Key Changes from Previous Design
421+
## Key Design Points
416422

417-
1. **Behaviour signature**: `resolve/3` instead of `resolve/2`
423+
1. **Behaviour signature**: `resolve/3` with module_ref, context, runtime_info
418424
2. **Third parameter**: `runtime_info` with enactment context
419-
3. **MFA format**: `{Module, :resolve, [context]}` for easy passing
420-
4. **Helper functions**: `to_mfa/2` and `call_mfa/3` for convenience
425+
3. **Resolver format**: `{Module, [context]}` - function name implicit from behaviour
426+
4. **Helper functions**: `new/2` and `resolve/3` for convenience
421427
5. **Lazy loading**: Resolution happens at runtime, not upfront
428+
6. **No redundancy**: Function name omitted since behaviour defines it

0 commit comments

Comments
 (0)