Plurality ships optional building blocks for Ash applications: changes, validations, and calculations for noun inflection. These modules compile away to nothing if Ash isn't loaded — no extra dependencies required.
Changes
Auto-inflect an attribute from another attribute on create or update.
Pluralize
defmodule MyApp.Resource do
use Ash.Resource
attributes do
attribute :name, :string
attribute :table_name, :string
end
actions do
create :create do
change {Plurality.Ash.Changes.Pluralize, attribute: :table_name, from: :name}
end
end
endWhen :name is "user", :table_name is set to "users".
Options:
:attribute(atom, required) — the attribute to write the inflected form to:from(atom, required) — the source attribute to read from
If the source attribute is nil, the changeset is returned unchanged.
Singularize
change {Plurality.Ash.Changes.Singularize, attribute: :resource_name, from: :label}Same options as Pluralize. Writes the singular form of the source attribute.
Validations
Ensure an attribute value is in the expected inflected form.
PluralForm
validate {Plurality.Ash.Validations.PluralForm, attribute: :table_name}Fails validation if the attribute value is not in plural form. nil values
pass (use allow_nil? false on the attribute if presence is required).
Uncountable words like "software" pass since they are valid in plural
context.
Options:
:attribute(atom, required) — the attribute to validate
SingularForm
validate {Plurality.Ash.Validations.SingularForm, attribute: :resource_name}Same as PluralForm but validates the value is in singular form.
Calculations
Derive plural or singular forms without storing them as attributes.
Pluralize
calculations do
calculate :name_plural, :string, {Plurality.Ash.Calculations.Pluralize, attribute: :name}
endReturns the plural form of the source attribute. Returns nil if the source
is nil.
Options:
:attribute(atom, required) — the source attribute to inflect
Singularize
calculations do
calculate :name_singular, :string, {Plurality.Ash.Calculations.Singularize, attribute: :name}
endFull example
defmodule MyApp.Schema do
use Ash.Resource,
domain: MyApp.Admin,
data_layer: AshPostgres.DataLayer
attributes do
uuid_primary_key :id
attribute :name, :string, allow_nil?: false
attribute :table_name, :string
attribute :resource_name, :string
end
actions do
create :create do
accept [:name]
change {Plurality.Ash.Changes.Pluralize, attribute: :table_name, from: :name}
change {Plurality.Ash.Changes.Singularize, attribute: :resource_name, from: :name}
end
update :update do
accept [:name]
validate {Plurality.Ash.Validations.PluralForm, attribute: :table_name}
validate {Plurality.Ash.Validations.SingularForm, attribute: :resource_name}
end
end
calculations do
calculate :display_plural, :string, {Plurality.Ash.Calculations.Pluralize, attribute: :name}
calculate :display_singular, :string, {Plurality.Ash.Calculations.Singularize, attribute: :name}
end
endConditional compilation
All Ash integration modules are wrapped in if Code.ensure_loaded?/1 checks.
If Ash is not in your dependency tree, these modules don't exist and have zero
impact on compilation or runtime. You don't need to do anything to enable or
disable them — it's automatic.