Project

fmt

0.01
The project is in a healthy, maintained state
CLI Templating System and String Formatter
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

Lines of Code GEM Version GEM Downloads Tests Ruby Style Sponsors Twitter Follow

CLI Templating System and String Formatter

Fmt is a powerful and flexible templating system and string formatter for Ruby, designed to streamline the creation of command-line interfaces and enhance general-purpose string formatting.

Table of Contents

  • Getting Started
  • Usage
    • Macros
    • Pipelines
    • Supported Methods
      • Rainbow GEM
    • Composition
      • Embedded Templates
    • Customizing Fmt
  • Kernel Refinement
    • fmt(object, *pipeline)
    • fmt_print(object, *pipeline)
    • fmt_puts(object, *pipeline)
  • Performance
  • Sponsors

Getting Started

Install the required dependencies:

bundle add rainbow # <- optional, for color support
bundle add fmt

Then, require the necessary libraries in your Ruby file:

require "rainbow" # <- optional, for color support
require "fmt"

Usage

Fmt uses Ruby's native format specifiers to create templates:

  • "%s" - Standard format specifier
  • "%{variable}" - Named format specifier
  • "%<variable>s" - Named format specifier (alternative syntax)

Macros

Formatting macros are appended to format specifiers to modify the output:

Fmt("%s|>capitalize", "hello world!") # => "Hello world!"
Fmt("%{msg}|>capitalize", msg: "hello world!") # => "Hello world!"

Macros can accept arguments:

Fmt("%s|>prepend('Hello ')", "world!") # => "Hello world!"
Fmt("%{msg}|>prepend('Hello ')", msg: "world!") # => "Hello world!"

Pipelines

Macros can be chained to create a formatting pipeline:

Fmt("%s|>prepend('Hello ')|>ljust(32, '.')|>upcase", "world!") # => "HELLO WORLD!...................."
Fmt("%{msg}|>prepend('Hello ')|>ljust(32, '.')|>upcase", msg: "world!") # => "HELLO WORLD!...................."

Pipelines are processed left to right, with the return value from the preceding macro serving as the starting value for the next macro.

Arguments and return values can be of any type:

Fmt("%p|>partition(/:/)|>last|>delete_suffix('>')", Object.new) # => "0x000000011f33bc68"

Supported Methods

Most public instance methods on the following classes are supported:

Array, Date, DateTime, FalseClass, Float, Hash, Integer, NilClass, Range, Regexp, Set, StandardError, String, Struct, Symbol, Time, TrueClass

Extension methods from libraries like ActiveSupport will also be available if the library is required before Fmt.

Rainbow GEM

Color and style support is available if your project includes the Rainbow GEM:

template = "%{msg}|>cyan|>bold|>underline"
Fmt(template, msg: "Hello World!")
#=> "\e[36m\e[1m\e[4mHello World!\e[0m"

Composition

Templates can include multiple format strings with distinct pipelines:

template = "Date: %<date>.10s|>magenta -- %{msg}|>titleize|>bold"
Fmt(template, date: Time.now, msg: "this is cool")
#=> "Date: \e[35m2024-09-21\e[0m -- \e[1mThis Is Cool\e[0m"

Embedded Templates

Embedded templates can be nested within other templates:

template = "%{msg}|>faint {{%{embed}|>bold}}"
Fmt(template, msg: "Look Ma...", embed: "I'm embedded!")
#=> "\e[2mLook Ma...\e[0m \e[1mI'm embedded!\e[0m"

Embeds can have their own pipelines:

template = "%{msg}|>faint {{%{embed}|>bold}}|>underline"
Fmt(template, msg: "Look Ma...", embed: "I'm embedded!")
#=> "\e[2mLook Ma...\e[0m \e[1m\e[4mI'm embedded!\e[0m"

Embeds can be deeply nested:

template = "%{msg}|>faint {{%{embed}|>bold {{%{deep_embed}|>red|>bold}}}}"
Fmt(template, msg: "Look Ma...", embed: "I'm embedded!", deep_embed: "And I'm deeply embedded!")
#=> "\e[2mLook Ma...\e[0m \e[1mI'm embedded!\e[0m \e[31m\e[1mAnd I'm deeply embedded!\e[0m"

Embeds can also span multiple lines:

template = <<~T
  Multiline:
  %{one}|>red {{
    %{two}|>blue {{
      %{three}|>green
    }}|>bold
  }}
T
Fmt(template, one: "Red", two: "Blue", three: "Green")
#=> "Multiline:\n\e[31mRed\e[0m \n  \e[34mBlue\e[0m \e[1m\n    \e[32mGreen\e[0m\n  \e[0m\n\n"

Customizing Fmt

Add custom filters by registering them with Fmt:

Fmt.register([Object, :shuffle]) { |*args, **kwargs| to_s.chars.shuffle.join }
Fmt("%s|>shuffle", "This don't make no sense.")
#=> "de.nnoTtsnh'oeek  ssim a "

Run a Ruby block with temporary filters without officially registering them:

Fmt.with_overrides([Object, :red] => proc { |*args, **kwargs| Rainbow(self).crimson.bold }) do
  Fmt("%s|>red", "This is customized red!")
  #=> "\e[38;5;197m\e[1mThis is customized red!\e[0m"
end

Fmt("%s|>red", "This is original red!")
#=> "\e[31mThis is original red!\e[0m"

Kernel Refinement

Fmt provides a kernel refinement that adds convenient methods for formatting and outputting text directly. To use these methods, you need to enable the refinement in your code:

using Fmt::KernelRefinement

Once enabled, you'll have access to the following methods:

fmt(object, *pipeline)

This method formats an object using a different pipeline syntax:

fmt("Hello, World!", :bold) # => "\e[1mHello, World!\e[0m"
fmt(:hello, :underline) # => "\e[4mhello\e[0m"
fmt(Object.new, :red) # => "\e[31m#<Object:0x00007f9b8b0b0a08>\e[0m"

fmt_print(object, *pipeline)

This method formats an object and prints it to STDOUT without a newline:

fmt_print("Hello, World!", :italic) # Prints: "\e[3mHello, World!\e[0m"
fmt_print(:hello, :green) # Prints: "\e[32mhello\e[0m"

fmt_puts(object, *pipeline)

This method formats an object and prints it to STDOUT with a newline:

fmt_puts("Hello, World!", :bold, :underline) # Prints: "\e[1m\e[4mHello, World!\e[0m\n"
fmt_puts(:hello, :magenta) # Prints: "\e[35mhello\e[0m\n"

These methods provide a convenient way to use Fmt's formatting capabilities directly in your code without explicitly calling the Fmt method.

You can pass any number of macros when using these methods:

fmt("Important!", :red, :bold, :underline)
# => "\e[31m\e[1m\e[4mImportant!\e[0m"

fmt_puts("Warning:", :yellow, :italic)
# Prints: "\e[33m\e[3mWarning:\e[0m\n"

These kernel methods make it easy to integrate Fmt's powerful formatting capabilities into your command-line interfaces or any part of your Ruby application where you need to format and output text.

Performance

Fmt is optimized for performance:

  • Tokenization: Uses StringScanner and Ripper to parse and tokenize templates
  • Caching: Stores an Abstract Syntax Tree (AST) representation of each template, pipeline, and macro
  • Speed: Current benchmarks show an average pipeline execution time of under 0.3 milliseconds

Complex pipelines may take slightly longer to execute.

Sponsors

Proudly sponsored by