| name | perl-file-sharedir |
| description | File::ShareDir — packaging and accessing non-code data files (templates, schemas, configs, skills) in Perl distributions. |
| user-invocable | true |
File::ShareDir — Distribution Share Files
Share files are non-code data files (templates, schemas, configs, word lists, skill definitions) shipped with a Perl distribution and accessible at runtime.
Directory layout
my-dist/
lib/
share/ ← convention, configurable
templates/
schema.json
claude-skill.md
dist.ini
Dist::Zilla setup
[ShareDir] is part of @Basic, which is included in [@Author::GETTY]. So no extra config needed — just put files in share/ and they get packaged automatically.
To override the directory name (default is share/):
[ShareDir]
dir = data
Runtime access
After installation (production)
use File::ShareDir 'dist_dir';
use Path::Tiny;
my $share = path( dist_dir('My-Dist') );
my $template = $share->child('templates/main.html')->slurp_utf8;
Key functions:
| Function | Returns |
|---|
dist_dir('Dist-Name') | Share directory path for a distribution |
dist_file('Dist-Name', 'file.txt') | Full path to a specific file |
module_dir('Module::Name') | Per-module share dir (rarely used) |
module_file('Module::Name', 'f.txt') | Per-module file (rarely used) |
Important: Dist name uses hyphens (App-karr), not colons.
Development fallback
dist_dir() only works after install. For development, fall back via %INC:
sub _find_share_dir {
eval {
require File::ShareDir;
my $dir = File::ShareDir::dist_dir('My-Dist');
return path($dir) if path($dir)->is_dir;
};
my $module_path = $INC{'My/Dist/Module.pm'};
if ($module_path) {
my $share = path($module_path)->parent(4)->child('share');
return $share if $share->is_dir;
}
die "Could not find share directory. Is My-Dist properly installed?\n";
}
Parent count: count the path components in lib/My/Dist/Module.pm (that's 4).
Alternative: File::ShareDir::ProjectDistDir
Zero-config development access (works without install):
use File::ShareDir::ProjectDistDir;
Trade-off: extra dependency, magic. The %INC fallback is more explicit.
Testing share files
Use Test::File::ShareDir to set up share dirs in tests:
use Test::File::ShareDir -share => {
-dist => { 'My-Dist' => 'share/' },
};
use File::ShareDir 'dist_dir';
my $dir = dist_dir('My-Dist');
cpanfile dependency
requires 'File::ShareDir';
on test => sub {
requires 'Test::File::ShareDir';
};
Common patterns
Ship a config/template
sub default_config_path {
return path(dist_dir('My-Dist'))->child('default-config.yml');
}
Ship a Claude Code skill (like App::karr)
share/
claude-skill.md
my $share = find_share_dir();
my $skill = $share->child('claude-skill.md')->slurp_utf8;
path('.claude/skills/myapp/SKILL.md')->spew_utf8($skill);
Ship JSON schemas (like OpenAPI-Modern)
my $share_dir = dist_dir('OpenAPI-Modern');
foreach my $file (path($share_dir)->children(qr/\.json$/)) {
register_schema($file);
}
Gotchas
- dist_dir() dies if the dist isn't installed — always wrap in eval for dev fallback
- Dist name format:
App-karr not App::karr — hyphens, not colons
- [@Author::GETTY] includes
[ShareDir] via @Basic — no extra dist.ini config needed
- Files must exist at build time —
dzil build snapshots share/ into the tarball
- No write access — share dir may be in a system-owned path after install; never write to it