Build Status Gem License

String::Builder

Modified and extended port of the String::Builder IO-style initializer for the String class of the Crystal programming language in the form of a Ruby gem refinement module.

Methods

There are three new methods in this extension of the String class:

Instance methods

String#build

Takes a block yielding a new builder string, and appends the builder string to a duplicate of the original String object, self.

Examples
foobar = 'foo'.build do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "foobar"
foo = 'foo'

foobar = foo.build do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "foobar"

String#build!

Takes a block yielding a new builder string, and appends the builder string to the original String object, self.

NOTE: This mutates the original string, as indicated by the bang !.

Example
foobar = 'foo'

foobar.build! do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "foobar"

Class methods

String.build

Takes an arbitrary object and a block yielding a new string builder, and appends the builder string to a duplicate of the object parameter converted to a string (with to_s).

If no block is given, then the object converted to a string (with to_s) is returned.

Examples
foobar = String.build do |s|
  s << 'fii'
  s.gsub!('ii','oo')
  s << 'bar'
end

foobar #=> "foobar"
foobar = String.build 'foo' do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "foobar"
foobar = String.build 3 do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "3bar"
foo = 'foo'

foobar = String.build foo do |s|
  s << 'bop'
  s.gsub!('op','ar')
end

foobar #=> "foobar"
foo #=> "foo"

String.[]

Takes arbitrarily many objects (with splat), converts them to strings and contatenates them (takes the product with the empty string).

Examples
String[]                       #=> ""
String[3]                      #=> "3"
String['Hello','World','!']    #=> "HelloWorld!"
String[{k: 'v'}, 3, %i[a b c]] #=> "{:k=>\"v\"}3[:a, :b, :c]"
String[*['a', 2, :z]]          #=> "a2z"

Detailed example

This example shows how to make a simple logger by constructing log messages with String::Builder.

Suppose we want a Logger class that allows us to do the following:

logger = Logger.new

logger.error 'String::Builder is good?'
#=> [03:54:53s] (lib/string-builder.rb) ERROR » String::Builder is good!
logger.success 'String::Builder is good?'
#=> [03:54:55s] (lib/string-builder.rb) SUCCESS » String::Builder is good!
logger.info 'String::Builder is good?'
#=> [03:54:57s] (lib/string-builder.rb) INFO » String::Builder is good!
logger.warning 'String::Builder is good?'
#=> [03:54:59s] (lib/string-builder.rb) WARNING » String::Builder is good!

Class method - String.build

require 'string/builder'

class Logger
  using String::Builder
  %i[error success info warning].each do |severity|
    define_method(severity) do |message|
      time = Time.now.strftime("[%H:%M:%Ss]")
      String.build time do |s|
        s << " (#{__FILE__})"
        s << " #{severity.to_s.upcase} » #{message}"
        s.gsub!('?','!')
      end
    end
  end
end

Instance method - String#build

The class shown above can use the String#build instance method to achieve the same functionality.

require 'string/builder'

class Logger
  using String::Builder
  %i[error success info warning].each do |severity|
    define_method(severity) do |message|
      time = Time.now.strftime("[%H:%M:%Ss]")
      time.build do |s|
        s << " (#{__FILE__})"
        s << " #{severity.to_s.upcase} » #{message}"
        s.gsub!('?','!')
      end
    end
  end
end

Installation

Add this line to your application's Gemfile:

gem 'string-builder'

And then execute:

$ bundle

Or install it yourself as:

$ gem install string-builder

Usage

This extension is in the form of a refinement. This means that you will have to call the following using directive within the scope that you want the String class to be extended with String::Builder methods:

require 'string/builder'
using String::Builder

Though you should typically avoid doing this in the global scope (unless you really need to), and instead only use the extension where you need it - inside your specific modules or classes:

require 'string/builder'

class A
  using String::Builder
  # CAN use String::Builder methods in this class
end

module B
  # CANNOT use String::Builder methods in this module
end

# CANNOT use String::Builder methods in the global scope

Further information

For more information about string-building in Ruby and Crystal, read this blog post.