Inflection & Case Filters
CodeBaker adds a set of Pebble filters for turning one variable into every naming style a feature needs: class names, table names, route segments, constants and labels.
Only entity is typed in this example. Every other name is computed from it, from the top down:
https://codebaker.dev/examples/naming.zipNeeds the CodeBaker plugin and an open project. Another IDE, or the button does nothing? Copy the link, then in the IDE right-click any folder → New → Generate from Template → Install Template from URL… and paste it. You always get a confirmation dialog before anything is installed.
{
// The folder name when the template is installed under .CodeBaker/
id: "naming",
name: "Naming",
// Only `entity` is typed. The others are computed from it, from the top down.
vars: {
entity: "BlogPost",
table: "{{ entity | tableize }}",
route: "{{ entity | pluralize | dasherize }}",
foreign: "{{ entity | foreignKey }}",
constant: "{{ entity | constantCase }}",
property: "{{ entity | variable }}",
},
}
# {{ entity }}
| Where it is used | Name |
|---|---|
| Class | `{{ entity }}` |
| Table | `{{ table }}` |
| URL | `/{{ route }}` |
| Foreign key | `{{ foreign }}` |
| Constant | `{{ constant }}` |
| Property | `${{ property }}` |
- entity
- BlogPost
- table
- {{ entity | tableize }}
- route
- {{ entity | pluralize | dasherize }}
- foreign
- {{ entity | foreignKey }}
- constant
- {{ entity | constantCase }}
- property
- {{ entity | variable }}
# BlogPost
| Where it is used | Name |
|---|---|
| Class | `BlogPost` |
| Table | `blog_posts` |
| URL | `/blog-posts` |
| Foreign key | `blog_post_id` |
| Constant | `BLOG_POST` |
| Property | `$blogPost` |
The filters in that example, and a few more:
{{ entity | pluralize }} {# BlogPost -> BlogPosts #}
{{ entity | tableize }} {# BlogPost -> blog_posts #}
{{ entity | variable }} {# BlogPost -> blogPost #}
{{ entity | dasherize }} {# BlogPost -> blog-post #}
Filters are used inside a Pebble expression, in two main places:
- In template files and in computed
varsofcodebaker.config.json5. - In
codebaker.advanced.json5, whosetargetanddatavalues are rendered by Pebble too, for exampletarget: "{{ entity | tableize }}.php".
{
"vars": {
"entity": "BlogPost",
"table": "{{ entity | tableize }}", // blog_posts
"routePrefix": "{{ entity | pluralize | dasherize }}", // blog-posts
"fk": "{{ entity | foreignKey }}", // blog_post_id
}
}
Variables are resolved from top to bottom, so entity must be defined before table, routePrefix and fk, which use it. The Values and Variables lesson explains how.
Names of files and folders only get plain text substitution of simple placeholders such as ___var___ or {{ var }}. They are not run through Pebble, so a filter such as {{ entity | tableize }} written directly in a file name is not evaluated and stays as written. For the full Pebble syntax in an output name, use one of two ways: compute the value in a vars entry (like table above) and use it as ___table___ in the name, or keep a plain file name in the template and set the output name with a target in codebaker.advanced.json5, which is rendered by Pebble first (see Advanced Templates).
Any Input Style Works
Case filters split the input into words first, so these inputs all produce the same result:
| Input | camelize | underscore |
|---|---|---|
user_profile | UserProfile | user_profile |
user-profile | UserProfile | user_profile |
user profile | UserProfile | user_profile |
userProfile | UserProfile | user_profile |
UserProfile | UserProfile | user_profile |
USER_PROFILE | UserProfile | user_profile |
Acronyms become ordinary words: HTMLParser → HtmlParser / html_parser. Digits stay attached to the word before them: address1Line → address1_line.
Inflection
| Filter | Example | Result |
|---|---|---|
pluralize | Person | People |
pluralize(count) | Item with count = 1 | Item (singular when the count is the number 1 or -1) |
singularize | categories | category |
tableize | UserCategory | user_categories |
classify | user_categories | UserCategory |
foreignKey | UserCategory | user_category_id |
foreignKey('_uuid') | Users | user_uuid |
pluralize and singularize change only the last word and keep its casing, so compound names stay intact:
| Input | pluralize |
|---|---|
UserPerson | UserPeople |
order_item | order_items |
ORDER_ITEM | ORDER_ITEMS |
App\Models\Category | App\Models\Categories |
Both filters leave a word alone if it is already in the target form (users | pluralize → users). Irregular and uncountable words are handled, including common code words: child/children, criterion/criteria, status/statuses, database/databases, index/indices, sheep, news, series, software, metadata, feedback. Words ending in data (such as metadata) and the word media are left unchanged in both directions, so data | singularize stays data. Two irregular words are the exception when pluralizing: datum gives data and medium gives media.
Case Conversion
Each filter and its aliases do the same thing, so use whichever name your team knows.
| Filter | Alias(es) | blog_post_id → |
|---|---|---|
camelize | pascalCase, studlyCase | BlogPostId |
variable | camelCase | blogPostId |
underscore | snakeCase | blog_post_id |
dasherize | kebabCase | blog-post-id |
humanize | titleCase | Blog Post Id |
constantCase | screamingSnakeCase | BLOG_POST_ID |
dotCase | blog.post.id | |
pathCase | blog/post/id | |
spaceCase | blog post id | |
trainCase | Blog-Post-Id | |
sentenceCase | Blog post id | |
flatCase | blogpostid | |
upperFlatCase | BLOGPOSTID | |
delimit('::') | blog::post::id |
String Helpers
| Filter | Example | Result |
|---|---|---|
slug | Crème Brûlée à la carte! | creme-brulee-a-la-carte |
slug('_', false) | My Blog Post! | My_Blog_Post |
ucfirst | userName | UserName |
lcfirst | UserName | userName |
slug(separator = '-', lowercase = true) converts accented letters to plain ASCII and replaces everything else with the separator.
Chaining and Lists
Filters chain left to right:
{{ 'UserCategory' | pluralize | constantCase }} {# USER_CATEGORIES #}
A list is converted item by item, so it combines with Pebble's join:
SELECT {{ fields | underscore | join(', ') }} FROM {{ entity | tableize }};
{# fields = ["firstName", "LastName"], entity = "BlogPost"
-> SELECT first_name, last_name FROM blog_posts; #}
A missing or null variable renders as an empty string, the same as without a filter.
Things to Watch For
slug,ucfirstandlcfirstdo not split words:BlogPost | sluggivesblogpost, notblog-post. Usedasherizefor that.pluralize(count)treats only a numeric1or-1as singular. The text'1'is not a number and gets pluralized.humanizeandtitleCasedo not strip a trailing_id:user_id | humanizegivesUser Id.