npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pluto-path

v1.2.0

Published

Create a Pluto dependency injection module from files in a path or paths

Downloads

42

Readme

pluto-path

Create and bootstrap an app from files in a path or paths using the Pluto dependency injection package.

| Branch | Status | | ------------- |:------------- | | Master | Build Status Coverage Status NSP Status | | All | Build Status |

Why?

This package aims to solve two problems:

  1. Bootstrapping. There are many example Express/Hapi/etc. applications where a chain of index.js files require a bunch of routes and other bits. I find this annoying. When I create a new part of my app, I want it to Just Work without extra boilerplate.
  2. Testing. The key to good testing isn't writing tests: it's writing good, testable code. When unit testing, in particular, we want to test one thing at a time. But what about when our one thing uses other things? By injecting those other things, often called collaborators, we can pass mocks or fakes to our code under test.

Usage

Simplified Options

'use strict'

const path = require('path')
const plutoPath = require('pluto-path')

plutoPath(path.join(__dirname, 'my-directory')) // you can pass a single search path or array of them
  .then(function (app) {
    // `app` holds a Map from filenames to their components.
    // It's created by calling pluto's `bootstrap(...)` function.
    // Use it if you want to do interact with components after they're
    // wired together.
  })
  // Don't forget about errors!
  .catch(err => {
    console.error(err.stack) // eslint-disable-line no-console
    process.exitCode = 1
  })

Binding Types

This module will instantiate components in different ways:

| Binding | Used When | Meaning | | ---------------- | --------- | ------- | | Factory Function | File exports a function, and starts with a lower-case letter. | The module's export will be called as a regular function, and the result will be bound to the file name. | | Constructor | File exports a function, and starts with a capital letter | The module's export will be bound as a constructor with new, and the result will be bound to the file name. | | Instance | File does not export a function | The module's export will be used as-is. |

See the Pluto Documentation for more details.

Full Options

Since the default include and exclude options work for most projects and the path is often the only meaningful property, you can pass a string or array of strings for the path property instead of a full options object, as above. Alternately

| Property | Description | | -------- | ----------- | | path | string or array of absolute paths to search for files. Default: .. | | include | string or array of minimatch patterns. A file in the path(s) that match at least one pattern will be require(...)'d unless the file also matches an exclusion pattern. Default: ['**/*.js', '**/*.json'].| | exclude | string or array of minimatch patterns. Files in the path(s) that match at least one pattern will be excluded. Default: ['**/*Spec.js']. | | extraBindings | A function given the standard pluto bind object. Use when you'd like to specify additional options beyond what pluto-path can find on the filesystem. |

'use strict'

const path = require('path')
const plutoPath = require('pluto-path')

plutoPath({
    path: path.join(__dirname, 'my-directory'),
    include: ['**/*.js', '**/*.json'],
    exclude: ['**/*Spec.js'],
    extraBindings: (bind) => {
      bind('meaningOfLife').toInstance(42)
    }
  })
  .then(function (app) {
    // `app` holds a Map from filenames to their components.
    // It's created by calling pluto's `bootstrap(...)` function.
  })
  // Don't forget about errors!
  .catch(err => {
    console.error(err.stack) // eslint-disable-line no-console
    process.exitCode = 1
  })

Humble Opinionated Recommendations

Project Organization

There's usually two different kinds of files in an app:

  1. Long-lived components, like route handlers and server configuration. These need to be run exactly once and become a part of your app. Place these in an app folder.
  2. Utilities and such that don't have a life of their own, and which you don't want subject to dependency injection. Place these in a lib folder.
/
  /app        Bootstrap long-lived components
  /lib        Utilities and such you don't want to dependency-inject
  index.js    `main` file with initial bootstrapping

Instruct pluto-path to bootstrap the app folder and leave the lib folder alone. If you're not doing any fancy startup stuff and you're fine with other defaults, your index.js file might look like:

'use strict'

const path = require('path')
const plutoPath = require('pluto-path')

plutoPath(path.join(__dirname, 'app'))
  // Don't forget about errors!
  .catch(err => {
    console.error(err.stack) // eslint-disable-line no-console
    process.exitCode = 1
  })

Tests

You might notice that there's not test path, event though one of the main motivations for dependency injection is testability. Rather than use a separate test tree, I like to put my tests right next to the thing they're testing, with a Spec suffix, like:

/
  /app
    myThing.js
    myThingSpec.js

I am highly influenced by Uncle Bob's Principles of Object Oriented Design. In this case:

  • Common Closure Principle: Things that change together should be packaged together.

When it comes to unit testing, a test and the thing it tests unsurprisingly tend to change together, so I like to put them next to each other. Stepping back, this makes logical sense, too: why hunt deep down through two separate directory trees just to get to the two files you want to change? Putting tests next to the code they test reduces friction when writing tests and just makes life easier.

The default arguments to pluto-path assume this kind of organization. If you want to do something else, change the include and exclude options as you see fit.