Syndication Icon
Published December 28, 2015 Updated October 21, 2021
Pragmater Icon

Pragmater

Git Badge
Gem Version
Alchemists Style Guide
Circle CI Status

A command line interface that does one thing well by being entirely focused on managing/formatting source file directive pragmas (a.k.a. magic comments). Examples:

#! /usr/bin/env ruby
# frozen_string_literal: true
# encoding: UTF-8

With Ruby 2.3.0, frozen strings are supported via a pragma. This gem provides an easy way to insert or remove pragmas to single or multiple Ruby source files in order to benefit from improved memory and concurrency performance.

Features

  • Supports inserting a pragma or multiple pragmas to single or multiple source files.

  • Supports removing pragma(s) from single or multiple source files.

  • Supports file list filtering. Defaults to any file.

  • Ensures duplicate pragmas never exist.

  • Ensures pragmas are consistently formatted.

Screencasts

Screencast

Requirements

Setup

To install, run:

gem install pragmater

Usage

Command Line Interface (CLI)

From the command line, type: pragmater --help

Pragmater - A command line interface for managing/formatting source file pragma comments.

USAGE:
  -v, --version                            Show gem version.
  -h, --help                               Show this message.
  -c, --config [options]                   Manage gem configuration.
  -i, --insert [PATH]                      Insert pragam comments into files.
  -r, --remove [options]                   Remove pragam comments from files.

OPTIONS:

Insert/Remove:
      --comments a,b,c                     Add pragma comments.
      --includes a,b,c                     Add console support.

Configuration:
      --edit                               Edit configuration.
      --info                               Print configuration.

Both the --insert and --remove commands support the same options for specifying pragmas and/or included files. Example:

pragmater --insert --comments "# frozen_string_literal: true" --includes "Gemfile" "Guardfile" "Rakefile" ".gemspec" "config.ru" "bin/**/*" "**/*.rake" "**/*.rb"

The --insert and --remove commands default to the current working directory so a path isn’t necessary unless you want to run Pragmater in a directory structure other than your current working directory.

Customization

This gem can be configured via a global configuration: $HOME/.config/pragmater/configuration.yml

It can also be configured via XDG environment variables.

The default configuration is as follows:

:insert:
  :comments: []
  :includes: []
:remove:
  :comments: []
  :includes: []

Feel free to take the above configuration, modify, and save as your own custom configuration.yml.

The configuration.yml file can be configured as follows:

  • insert: Defines global/local comments and/or file include lists when inserting pragmas. The comments and includes options can be either a single string or an array of strings.

  • remove: Defines global/local comments and/or file include lists when removing pragmas. The comments and includes options can be either a single string or an array of strings.

Available Pragmas

With Ruby 2.3 and higher, the following pragmas are available:

  • # encoding: Defaults to UTF-8 but any supported encoding can be used. For a list of values, launch an IRB session and run Encoding.name_list.

  • # coding: The shorthand for # encoding:. Supports the same values as mentioned above.

  • # frozen_string_literal: Defaults to false but can take either true or false as a value. When enabled, Ruby will throw errors when strings are used in a mutable fashion.

  • # warn_indent: Defaults to false but can take either true or false as a value. When enabled, and running Ruby with the -w option, it’ll throw warnings for code that isn’t indented by two spaces.

Syntax

The pragma syntax allows for two kinds of styles. Example:

# encoding: UTF-8
# -*- encoding: UTF-8 -*-

Only the former syntax is supported by this gem as the latter syntax is more verbose and requires additional typing.

Precedence

When different multiple pragmas are defined, they all take precedence:

# encoding: binary
# frozen_string_literal: true

In the above example, both binary encoding and frozen string literals behavior will be applied.

When defining multiple pragmas that are similar, behavior can differ based on the kind of pragma used. The following walks through each use case so you know what to expect:

# encoding: binary
# encoding: UTF-8

In the above example, only the binary encoding will be applied while the UTF-8 encoding will be ignored (same principle applies for the coding pragma too).

# frozen_string_literal: false
# frozen_string_literal: true

In the above example, frozen string literal support will be enabled instead of being disabled.

# warn_indent: false
# warn_indent: true

In the above example, indentation warnings will be enabled instead of being disabled.

Frozen String Literals

Support for frozen string literals was added in Ruby 2.3.0. The ability to freeze strings within a source can be done by placing a frozen string pragma at the top of each source file. Example:

# frozen_string_literal: true

This is great for selective enablement of frozen string literals but might be too much work for some (even with the aid of this gem). As an alternative, frozen string literals can be enabled via the following Ruby command line option:

--enable=frozen-string-literal

It is important to note that, once enabled, this freezes strings program-wide – It’s an all or nothing option.

Regardless of whether you leverage the capabilities of this gem or the Ruby command line option mentioned above, the following Ruby command line option is available to aid debugging and tracking down frozen string literal issues:

--debug=frozen-string-literal

Ruby 2.3.0 also added the following methods to the String class:

  • String#+@: Answers a duplicated, mutable, string if not already frozen. Example:

    immutable = "test".freeze
    mutable = +immutable
    mutable.capitalize! # => "Test"
  • String#-@: Answers a immutable string if not already frozen. Example:

    mutable = "test"
    immutable = -mutable
    immutable.capitalize! # => FrozenError

You can also use the methods, shown above, for variable initialization. Example:

immutable = -"test"
mutable = +"test"

💡 The use of String#-@, specifically, was enhanced in Ruby 2.5.0 to deduplicate all instances of the same string thus reducing your memory footprint. This can be valuable in situations where you are not using the frozen string comment and need to selectively freeze strings.

Consistency

As an added bonus, this gem ensures pragmas for all analyzed files are formatted in a consistent style. This means there is always a space after the octothorpe (#). Here are multiple pragmas presented together for a visual comparison:

#! /usr/bin/env ruby
# encoding: UTF-8
# coding: UTF-8
# frozen_string_literal: true
# warn_indent: true

One oddity to the above is the use of # !/usr/bin/env ruby is not allowed but #! /usr/bin/env ruby is which is why spacing is slightly different for shell pragmas.

Development

To contribute, run:

git clone https://github.com/bkuhlmann/pragmater.git
cd pragmater
bin/setup

You can also use the IRB console for direct access to all objects:

bin/console

Tests

To test, run:

bundle exec rake

Versioning

Read Semantic Versioning for details. Briefly, it means:

  • Major (X.y.z) - Incremented for any backwards incompatible public API changes.

  • Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.

  • Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.

Code of Conduct

Read Code of Conduct for details.

Contributions

Read Contributions for details.

License

Read License for details.

History

Read Changes for details.

Credits

Engineered by Brooke Kuhlmann.