GithubHelp home page GithubHelp logo

mehonoshin / trailblazer-loader Goto Github PK

View Code? Open in Web Editor NEW

This project forked from trailblazer/trailblazer-loader

0.0 1.0 0.0 42 KB

Require concept files, models and more without any autoloading magic.

License: MIT License

Ruby 100.00%

trailblazer-loader's Introduction

Trailblazer::Loader

Generic loader for Trailblazer projects.

Reportedly works with Rails, Grape, Lotus, and Roda, and many more, for sure.

Rails users: This gem is bundled with trailblazer-rails.

Overview

While Trailblazer enforces a new file structure where you organize by concept, and not by technology, the naming and the structuring within each concept allows different styles.

Trailblazer-loader supports the following directory layouts concurrently.

Compound-Singular

Per concept, you have one file per abstraction layer (called a compound file). All is singular and reflects the namespace (except for operations which sit in the concept's namespace).

app
├── concepts
│   ├── comment
│   │   ├── callback.rb
│   │   ├── cell.rb
│   │   ├── contract.rb
│   │   ├── operation.rb
│   │   ├── policy.rb
│   │   └── views
│   │       ├── grid.haml
│   │       └── show.haml

You may nest concepts in concepts.

app
├── concepts
│   ├── comment
│   │   ├── contract.rb
│   │   ├── operation.rb
│   │   ├── admin
│   │       ├── contract.rb
│   │       └── operation.rb

Note: This is the structuring used in the Trailblazer book.

Explicit-Singular

Per concept, you have one directory per abstraction layer and one file per class. All is singular and reflects the namespace (except for operations which sit in the concept's namespace).

app
├── concepts
│   ├── comment
│   │   ├── contract
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── cell
│   │   │   └── form.rb
│   │   ├── operation
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   └── views
│   │       ├── grid.haml
│   │       └── show.haml

You may nest concepts in concepts.

app
├── concepts
│   ├── comment
│   │   ├── contract
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── operation
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── admin
│   │   │   └── contract
│   │   │       ├── create.rb
│   │   │       └── update.rb

Explicit-Plural

Per concept, you have one pluralized directory per abstraction layer and one file per class.

app
├── concepts
│   ├── comment
│   │   ├── contracts
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── cells
│   │   │   └── form.rb
│   │   ├── operations
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   └── views
│   │       ├── grid.haml
│   │       └── show.haml

And, yes, you may nest concepts in concepts.

app
├── concepts
│   ├── comment
│   │   ├── contracts
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── operations
│   │   │   ├── create.rb
│   │   │   └── update.rb
│   │   ├── admin
│   │   │   └── contracts
│   │   │       ├── create.rb
│   │   │       └── update.rb

Loading order

The loading order is identical for all styles.

  1. The loader finds all concept directories.
  2. Concept directories are sorted by nesting level, deeper nestings are loaded later as they might reference concepts they're nested in. For example, concepts/comment/admin might reuse existing code from concepts/comment.
  3. Per concept, files are lexically sorted, e.g. create.rb will be loaded before update.rb as we mostly do Update < Create.
  4. Per concept, operation files will be loaded after all other layer files have been required. This is because abstraction files like representers or contracts should not reference their operation. The operation, howver, as an orchestrating asset needs to refer to various abstraction objects.

Here's a sample of a explicit-singular session.

[
  "app/concepts/navigation/cell.rb",
  "app/concepts/session/impersonate.rb",
  "app/concepts/session/operation.rb",
  "app/concepts/user/operation.rb",
  "app/concepts/comment/cell/cell.rb",
  "app/concepts/comment/cell/grid.rb",
  "app/concepts/comment/operation/create.rb",
  "app/concepts/api/v1.rb",
  "app/concepts/thing/callback/default.rb",
  "app/concepts/thing/callback/upload.rb",
  "app/concepts/thing/cell.rb",
  "app/concepts/thing/cell/decorator.rb",
  "app/concepts/thing/cell/form.rb",
  "app/concepts/thing/cell/grid.rb",
  "app/concepts/thing/contract/create.rb",
  "app/concepts/thing/contract/update.rb",
  "app/concepts/thing/policy.rb",
  "app/concepts/thing/signed_in.rb",
  "app/concepts/thing/operation/create.rb",
  "app/concepts/thing/operation/delete.rb",
  "app/concepts/thing/operation/show.rb",
  "app/concepts/thing/operation/update.rb",
  "app/concepts/api/v1/comment/representer/show.rb",
  "app/concepts/api/v1/comment/operation/create.rb",
  "app/concepts/api/v1/comment/operation/show.rb",
  "app/concepts/api/v1/thing/representer/create.rb",
  "app/concepts/api/v1/thing/representer/index.rb",
  "app/concepts/api/v1/thing/representer/show.rb",
  "app/concepts/api/v1/thing/operation/create.rb",
  "app/concepts/api/v1/thing/operation/index.rb",
  "app/concepts/api/v1/thing/operation/update.rb"
]

Installation

Add this line to your application's Gemfile:

gem 'trailblazer-loader'

You do not need this step should you use one of the following binding gems.

API

Trailblazer::Loader.new.() { |file| require_dependency(File.join(Rails.application.root, file)) }

Per default, Trailblazer-loader will use app/concepts as the root path for the file search. Change that with the :concepts_root option.

Trailblazer::Loader.new.(concepts_root: "./concepts/") { |file| require_relative(file) }

Note that :concepts_root needs a trailing slash.

Mixing

Note that you're free to mix these styles the way it feels right for your project.

For example, you can have compound files and explicit layout in one concept.

app
├── concepts
│   ├── comment
│   │   ├── contract.rb     - compound vs.
│   │   ├── operation       -  explicit directory
│   │   │   ├── create.rb
│   │   │   └── update.rb

Namespacing Operations

Normally, operations in Trailblazer use the concept's namespace, e.g. Comment::Create, even though they can sit in an explicit file.

app
├── concepts
│   ├── comment
│   │   ├── operation       - explicit directory
│   │   │   ├── create.rb   -   contains Comment::Create
│   │   │   └── update.rb

You are free to namespace your operations, if you like that better.

module Comment::Operation
  class Create < Trailblazer::Operation

Debugging

Turn on debugging as follows.

Trailblazer::Loader.new.(debug: true) { |file| require_relative("../#{file}") }

This will print the file list before requiring them.

TODO: document PrintFiles

Booting your app fails because the loading order is incorrect? This happens, as we can't cover every possible combination.

In any case, you can use require or require_relative and load files manually in the file depending on a specific class.

For example, say you derive in another order and you're using the explicit layout.

require_relative "update.rb"
class Comment::Create < Comment::Update

Instead of painfully reconfiguring, require explicitly and save yourself a lot of pain. BTW, that's how every other programming language does dependency management and even Matz is not too happy about autoloading anymore.

Customizing

Trailblazer-loader allows you to inject your own sorting and filtering logic, should you refuse to go mainstream.

License

The gem is available as open source under the terms of the MIT License.

trailblazer-loader's People

Contributors

apotonick avatar pnikolov avatar hermanverschooten avatar alexand avatar rkushnir avatar ferdinandrosario avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.