{"id":13877874,"url":"https://github.com/hopsoft/fmt","last_synced_at":"2025-05-07T16:05:59.716Z","repository":{"id":250267357,"uuid":"833991333","full_name":"hopsoft/fmt","owner":"hopsoft","description":"CLI Templating System and String Formatter","archived":false,"fork":false,"pushed_at":"2024-11-13T17:26:30.000Z","size":67,"stargazers_count":31,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-07T14:52:16.122Z","etag":null,"topics":["ruby","ruby-gem","string-manipulation","template-engine"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hopsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-26T07:36:07.000Z","updated_at":"2024-12-27T06:27:35.000Z","dependencies_parsed_at":"2024-08-17T12:30:07.110Z","dependency_job_id":"20f422df-f93f-43f2-9bad-f404b0df0426","html_url":"https://github.com/hopsoft/fmt","commit_stats":null,"previous_names":["hopsoft/fmt"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hopsoft","download_url":"https://codeload.github.com/hopsoft/fmt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233128205,"owners_count":18629046,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","ruby-gem","string-manipulation","template-engine"],"created_at":"2024-08-06T08:01:33.704Z","updated_at":"2025-01-09T02:50:29.402Z","avatar_url":"https://github.com/hopsoft.png","language":"Ruby","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://blog.codinghorror.com/the-best-code-is-no-code-at-all/\"\u003e\n    \u003cimg alt=\"Lines of Code\" src=\"https://img.shields.io/badge/loc-1050-47d299.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://rubygems.org/gems/fmt\"\u003e\n    \u003cimg alt=\"GEM Version\" src=\"https://img.shields.io/gem/v/fmt\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://rubygems.org/gems/fmt\"\u003e\n    \u003cimg alt=\"GEM Downloads\" src=\"https://img.shields.io/gem/dt/fmt\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/hopsoft/fmt/actions\"\u003e\n    \u003cimg alt=\"Tests\" src=\"https://github.com/hopsoft/fmt/actions/workflows/tests.yml/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/testdouble/standard\"\u003e\n    \u003cimg alt=\"Ruby Style\" src=\"https://img.shields.io/badge/style-standard-168AFE?logo=ruby\u0026logoColor=FE1616\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/sponsors/hopsoft\"\u003e\n    \u003cimg alt=\"Sponsors\" src=\"https://img.shields.io/github/sponsors/hopsoft?color=eb4aaa\u0026logo=GitHub%20Sponsors\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/hopsoft\"\u003e\n    \u003cimg alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/url?label=%40hopsoft\u0026style=social\u0026url=https%3A%2F%2Ftwitter.com%2Fhopsoft\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# CLI Templating System and String Formatter\n\n**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.\n\n\u003c!-- Tocer[start]: Auto-generated, don't remove. --\u003e\n\n## Table of Contents\n\n- [Getting Started](#getting-started)\n- [Usage](#usage)\n  - [Macros](#macros)\n  - [Pipelines](#pipelines)\n  - [Supported Methods](#supported-methods)\n    - [Rainbow GEM](#rainbow-gem)\n  - [Composition](#composition)\n    - [Embedded Templates](#embedded-templates)\n  - [Customizing Fmt](#customizing-fmt)\n- [Kernel Refinement](#kernel-refinement)\n  - [`fmt(object, *pipeline)`](#fmtobject-pipeline)\n  - [`fmt_print(object, *pipeline)`](#fmt_printobject-pipeline)\n  - [`fmt_puts(object, *pipeline)`](#fmt_putsobject-pipeline)\n- [Performance](#performance)\n- [Sponsors](#sponsors)\n\n\u003c!-- Tocer[finish]: Auto-generated, don't remove. --\u003e\n\n## Getting Started\n\nInstall the required dependencies:\n\n```sh\nbundle add rainbow # \u003c- optional, for color support\nbundle add fmt\n```\n\nThen, require the necessary libraries in your Ruby file:\n\n```ruby\nrequire \"rainbow\" # \u003c- optional, for color support\nrequire \"fmt\"\n```\n\n## Usage\n\nFmt uses Ruby's native [format specifiers](https://ruby-doc.org/3.3.5/format_specifications_rdoc.html) to create templates:\n\n- `\"%s\"` - Standard format specifier\n- `\"%{variable}\"` - Named format specifier\n- `\"%\u003cvariable\u003es\"` - Named format specifier _(alternative syntax)_\n\n### Macros\n\nFormatting macros are appended to format specifiers to modify the output:\n\n\u003c!-- test_e798c3 --\u003e\n\n```ruby\nFmt(\"%s|\u003ecapitalize\", \"hello world!\") # =\u003e \"Hello world!\"\nFmt(\"%{msg}|\u003ecapitalize\", msg: \"hello world!\") # =\u003e \"Hello world!\"\n```\n\nMacros can accept arguments:\n\n\u003c!-- test_1707d2  --\u003e\n\n```ruby\nFmt(\"%s|\u003eprepend('Hello ')\", \"world!\") # =\u003e \"Hello world!\"\nFmt(\"%{msg}|\u003eprepend('Hello ')\", msg: \"world!\") # =\u003e \"Hello world!\"\n```\n\n### Pipelines\n\nMacros can be chained to create a formatting pipeline:\n\n\u003c!-- test_425625 --\u003e\n\n```ruby\nFmt(\"%s|\u003eprepend('Hello ')|\u003eljust(32, '.')|\u003eupcase\", \"world!\") # =\u003e \"HELLO WORLD!....................\"\nFmt(\"%{msg}|\u003eprepend('Hello ')|\u003eljust(32, '.')|\u003eupcase\", msg: \"world!\") # =\u003e \"HELLO WORLD!....................\"\n```\n\nPipelines are processed left to right, with the return value from the preceding macro serving as the starting value for the next macro.\n\nArguments and return values can be of any type:\n\n\u003c!-- test_f55ae2 --\u003e\n\n```ruby\nFmt(\"%p|\u003epartition(/:/)|\u003elast|\u003edelete_suffix('\u003e')\", Object.new) # =\u003e \"0x000000011f33bc68\"\n```\n\n### Supported Methods\n\nMost public instance methods on the following classes are supported:\n\n`Array`, `Date`, `DateTime`, `FalseClass`, `Float`, `Hash`, `Integer`, `NilClass`, `Range`, `Regexp`, `Set`, `StandardError`, `String`, `Struct`, `Symbol`, `Time`, `TrueClass`\n\nExtension methods from libraries like ActiveSupport will also be available if the library is required before Fmt.\n\n#### Rainbow GEM\n\nColor and style support is available if your project includes the [Rainbow GEM](https://github.com/ku1ik/rainbow):\n\n\u003c!-- test_19c8ca --\u003e\n\n```ruby\ntemplate = \"%{msg}|\u003ecyan|\u003ebold|\u003eunderline\"\nFmt(template, msg: \"Hello World!\")\n#=\u003e \"\\e[36m\\e[1m\\e[4mHello World!\\e[0m\"\n```\n\n### Composition\n\nTemplates can include multiple format strings with distinct pipelines:\n\n\u003c!-- test_0dbfcd --\u003e\n\n```ruby\ntemplate = \"Date: %\u003cdate\u003e.10s|\u003emagenta -- %{msg}|\u003etitleize|\u003ebold\"\nFmt(template, date: Time.now, msg: \"this is cool\")\n#=\u003e \"Date: \\e[35m2024-09-21\\e[0m -- \\e[1mThis Is Cool\\e[0m\"\n```\n\n#### Embedded Templates\n\nEmbedded templates can be nested within other templates:\n\n\u003c!-- test_efee7a --\u003e\n\n```ruby\ntemplate = \"%{msg}|\u003efaint {{%{embed}|\u003ebold}}\"\nFmt(template, msg: \"Look Ma...\", embed: \"I'm embedded!\")\n#=\u003e \"\\e[2mLook Ma...\\e[0m \\e[1mI'm embedded!\\e[0m\"\n```\n\nEmbeds can have their own pipelines:\n\n\u003c!-- test_abb7ea --\u003e\n\n```ruby\ntemplate = \"%{msg}|\u003efaint {{%{embed}|\u003ebold}}|\u003eunderline\"\nFmt(template, msg: \"Look Ma...\", embed: \"I'm embedded!\")\n#=\u003e \"\\e[2mLook Ma...\\e[0m \\e[1m\\e[4mI'm embedded!\\e[0m\"\n```\n\nEmbeds can be deeply nested:\n\n\u003c!-- test_79e924 --\u003e\n\n```ruby\ntemplate = \"%{msg}|\u003efaint {{%{embed}|\u003ebold {{%{deep_embed}|\u003ered|\u003ebold}}}}\"\nFmt(template, msg: \"Look Ma...\", embed: \"I'm embedded!\", deep_embed: \"And I'm deeply embedded!\")\n#=\u003e \"\\e[2mLook Ma...\\e[0m \\e[1mI'm embedded!\\e[0m \\e[31m\\e[1mAnd I'm deeply embedded!\\e[0m\"\n```\n\nEmbeds can also span multiple lines:\n\n\u003c!-- test_054526 --\u003e\n\n```ruby\ntemplate = \u003c\u003c~T\n  Multiline:\n  %{one}|\u003ered {{\n    %{two}|\u003eblue {{\n      %{three}|\u003egreen\n    }}|\u003ebold\n  }}\nT\nFmt(template, one: \"Red\", two: \"Blue\", three: \"Green\")\n#=\u003e \"Multiline:\\n\\e[31mRed\\e[0m \\n  \\e[34mBlue\\e[0m \\e[1m\\n    \\e[32mGreen\\e[0m\\n  \\e[0m\\n\\n\"\n```\n\n### Customizing Fmt\n\nAdd custom filters by registering them with Fmt:\n\n\u003c!-- test_2cacce --\u003e\n\n```ruby\nFmt.register([Object, :shuffle]) { |*args, **kwargs| to_s.chars.shuffle.join }\nFmt(\"%s|\u003eshuffle\", \"This don't make no sense.\")\n#=\u003e \"de.nnoTtsnh'oeek  ssim a \"\n```\n\nRun a Ruby block with temporary filters without officially registering them:\n\n\u003c!-- test_7df4eb --\u003e\n\n```ruby\nFmt.with_overrides([Object, :red] =\u003e proc { |*args, **kwargs| Rainbow(self).crimson.bold }) do\n  Fmt(\"%s|\u003ered\", \"This is customized red!\")\n  #=\u003e \"\\e[38;5;197m\\e[1mThis is customized red!\\e[0m\"\nend\n\nFmt(\"%s|\u003ered\", \"This is original red!\")\n#=\u003e \"\\e[31mThis is original red!\\e[0m\"\n```\n\n## Kernel Refinement\n\nFmt 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:\n\n```ruby\nusing Fmt::KernelRefinement\n```\n\nOnce enabled, you'll have access to the following methods:\n\n### `fmt(object, *pipeline)`\n\nThis method formats an object using a different pipeline syntax:\n\n```ruby\nfmt(\"Hello, World!\", :bold) # =\u003e \"\\e[1mHello, World!\\e[0m\"\nfmt(:hello, :underline) # =\u003e \"\\e[4mhello\\e[0m\"\nfmt(Object.new, :red) # =\u003e \"\\e[31m#\u003cObject:0x00007f9b8b0b0a08\u003e\\e[0m\"\n```\n\n### `fmt_print(object, *pipeline)`\n\nThis method formats an object and prints it to STDOUT without a newline:\n\n```ruby\nfmt_print(\"Hello, World!\", :italic) # Prints: \"\\e[3mHello, World!\\e[0m\"\nfmt_print(:hello, :green) # Prints: \"\\e[32mhello\\e[0m\"\n```\n\n### `fmt_puts(object, *pipeline)`\n\nThis method formats an object and prints it to STDOUT with a newline:\n\n```ruby\nfmt_puts(\"Hello, World!\", :bold, :underline) # Prints: \"\\e[1m\\e[4mHello, World!\\e[0m\\n\"\nfmt_puts(:hello, :magenta) # Prints: \"\\e[35mhello\\e[0m\\n\"\n```\n\nThese methods provide a convenient way to use Fmt's formatting capabilities directly in your code without explicitly calling the `Fmt` method.\n\nYou can pass any number of macros when using these methods:\n\n```ruby\nfmt(\"Important!\", :red, :bold, :underline)\n# =\u003e \"\\e[31m\\e[1m\\e[4mImportant!\\e[0m\"\n\nfmt_puts(\"Warning:\", :yellow, :italic)\n# Prints: \"\\e[33m\\e[3mWarning:\\e[0m\\n\"\n```\n\nThese 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.\n\n## Performance\n\nFmt is optimized for performance:\n\n- Tokenization: Uses StringScanner and Ripper to parse and tokenize templates\n- Caching: Stores an Abstract Syntax Tree (AST) representation of each template, pipeline, and macro\n- Speed: Current benchmarks show an average pipeline execution time of under 0.3 milliseconds\n\nComplex pipelines may take slightly longer to execute.\n\n## Sponsors\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eProudly sponsored by\u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.clickfunnels.com?utm_source=hopsoft\u0026utm_medium=open-source\u0026utm_campaign=fmt\"\u003e\n    \u003cimg src=\"https://images.clickfunnel.com/uploads/digital_asset/file/176632/clickfunnels-dark-logo.svg\" width=\"575\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","funding_links":["https://github.com/sponsors/hopsoft"],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhopsoft%2Ffmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhopsoft%2Ffmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhopsoft%2Ffmt/lists"}