Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - curiosum-dev/contexted: Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations. · GitHub
Skip to content

Repository files navigation

Contexted

Tools for clean, maintainable Elixir & Phoenix contexts

Contact UsVisit CuriosumLicense: MIT

📦 Short overview

Contexts in Elixir & Phoenix are getting complicated over time. Cross-referencing, big modules and repetitiveness are the most common reasons for this problem.

Contexted arms you with a set of tools to maintain contexts well.

Hex version badgeActions StatusLicense badge



Note: Official documentation for contexted library is available on hexdocs.



📚 Table of Contents


✨ Features

  • Contexted.Tracer - trace and enforce definite separation between specific context modules.
  • Contexted.Delegator - divide the big context module into smaller parts and use delegations to build the final context.
  • Contexted.CRUD - auto-generate the most common CRUD operations whenever needed.

📥 Installation

Add the following to your mix.exs file:

defpdepsdo[{:contexted,"~> 0.3.4"}]end

Then run mix deps.get.


🧭 Step by step overview

To describe a sample usage of this library, let's assume that your project has three contexts:

  • Account
  • Subscription
  • Blog

Our goal, as the project grows, is to:

  1. Keep contexts separate and not create any cross-references. For this to work, we'll raise errors during compilation whenever such a cross-reference happens.
  2. Divide each context into smaller parts so that it is easier to maintain. In this case, we'll refer to each of these parts as Subcontext. It's not a new term added to the Phoenix framework but rather a term proposed to emphasize that it's a subset of Context. For this to work, we'll use delegates.
  3. Not repeat ourselves with common business logic operations. For this to work, we'll be using CRUD functions generator, since these are the most common.

Keep contexts separate

It's very easy to monitor cross-references between context modules with the contexted library.

First, add contexted as one of the compilers in mix.exs:

defprojectdo[...compilers: [:contexted]++Mix.compilers(),
...
]end

Next, define a list of contexts available in the app inside config file:

config:contexted,contexts: [# list of context modules goes here, for instance:# [App.Account, App.Subscription, App.Blog]]

And that's it. From now on, whenever you will cross-reference one context with another, you will see an error raised during compilation. Here is an example of such an error:

== Compilation error in file lib/app/accounts.ex ==
** (RuntimeError) You can't reference App.Blog context within App.Accounts context.

Read more about Contexted.Tracer and its options in docs.


Exclude files and folders from cross-references context check

In special cases, you may need to exclude certain folders or files from cross-reference checks due to project structure or naming conventions. To do this, add a list of exclusions in config exclude_paths option:

config:contexted,exclude_paths: ["app/test"]

Dividing each context into smaller parts

To divide big Context into smaller Subcontexts, we can use delegate_all/1 macro from Contexted.Delegator module.

Let's assume that the Account context has User, UserToken and Admin resources. Here is how we can split the context module:

# Users subcontextdefmoduleApp.Account.Usersdodefget_user(id)do...endend# UserTokens subcontextdefmoduleApp.Account.UserTokensdodefget_user_token(id)do...endend# Admins subcontextdefmoduleApp.Account.Adminsdodefget_admin(id)do...endend# Account contextdefmoduleApp.AccountdoimportContexted.Delegatordelegate_allApp.Account.Usersdelegate_allApp.Account.UserTokensdelegate_allApp.Account.Adminsend

From now on, you can treat the Account context module as the API for the "outside" world.

Instead of calling:

App.Account.Users.find_user(1)

You will simply do:

App.Account.find_user(1)

Being able to access docs and specs in auto-delegated functions

Both docs and specs are attached as metadata of module once it's compiled and saved as .beam. In reference to the example of App.Account context, it's possible that App.Account.Users will not be saved in .beam file before the delegate_all macro is executed. Therefore, first, all of the modules have to be compiled, and saved to .beam and only then we can create @doc and @spec of each delegated function.

As a workaround, in Contexted.Tracer.after_compiler/1 all of the contexts .beam files are first deleted and then recompiled. This is an opt-in functionality, as it extends compilation time. If you want to enable it, set the following config values:

config:contexted,app: :your_app_name,# replace 'your_app_name' with your real app nameenable_recompilation: true

You may also want to enable it only for certain environments, like dev.

Please also note that when this functionality is enabled, during the recompilation process, warnings are temporarily silenced to avoid logging conflict warnings. It will still log warnings as intended, during the first compilation, therefore it won't have any affect on normal compilation flow.

Read more about Contexted.Delegator and its options in docs.


Don't repeat yourself with CRUD operations

In most web apps CRUD operations are very common. Most of these, have the same pattern. Why not autogenerate them?

Here is how you can generate common CRUD operations for App.Account.Users:

defmoduleApp.Account.UsersdouseContexted.CRUD,repo: App.Repo,schema: App.Accounts.Userend

This will generate the following functions:

iex>App.Accounts.Users.__info__(:functions)[change_user: 1,change_user: 2,create_user: 0,create_user: 1,create_user!: 0,create_user!: 1,delete_user: 1,delete_user!: 1,get_user: 1,get_user!: 1,list_users: 0,update_user: 1,update_user: 2,update_user!: 1,update_user!: 2]

Read more about Contexted.CRUD and its options in docs.


🤝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See CONTRIBUTING.md for more details.

Development setup

Just clone the repository, install dependencies normally, develop and run tests. For running tests and static analysis tools, refer to GitHub Action workflow definition.


Media


Community


Contact


📄 License

Distributed under the MIT License. See LICENSE for more information.

About

Elixir library designed to help you manage the complexity of Phoenix contexts. It offers tools for module separation, subcontext creation, and auto-generating CRUD operations.

Topics

Resources

Code of conduct

Contributing

Stars

85 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages