Class: StringFormat

Inherits:
String
  • Object
show all
Defined in:
lib/stringformat.rb

Overview

StringFormat: A string format library that’s programmable.

Synopsis:

# up-front interface
f = StringFormat.new(
    "d" => proc { |item, num| num + ' ' + item } # %0.2d
    "s"  => proc { |item, num| item } # %s
)

s = f.new_string "my_string %s"

# StringFormat is just a subclass of String, so this works:

s % "hello there" # => "my_string hello there"

# something more complex (using base-class String methods): 

s[s.length - 2 .. s.length - 1] % "something new" # => "something new"

# add iteratively -- works with generated Format#new_string objects as well
f.add_format("f") do |item, num|
    num + ' ' + item
end

f.del_format("d")

# add a format that does not require an argument:
f.add_format("e") do
    Date.new.strftime("%s")
end

# and use it like such:

s = f.clone("string %e %f")
s % [1.2] => "string 12345667787 1.2"
s = f.clone("string %e")
s % nil => "string 12345667787"

# these also work on the string objects themselves, so you can add on for specific strings:

s.add_format("s") do |item, num|
    "monkeys around"
end

s % "foobar" # => "my_string monkeys around"

An improperly formatted string (one that is passed too many or too little
arguments for what is expected) will raise a StringFormat::FormatError
exception.
Author

Erik Hollensbe <[email protected]>

– TODO LIST

Spec conflict checking ++

Defined Under Namespace

Classes: FormatError

Constant Summary collapse

VERSION =
"0.0.1"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ StringFormat

takes a listing of specifications and procs. For a description of how to define formats, see Format#add_format.



71
72
73
74
75
76
77
# File 'lib/stringformat.rb', line 71

def initialize(*args)
    @format_table = args[0] || { }
    @format_table.to_hash unless @format_table.respond_to? :keys
    @format_leader = "%"

    super ""
end

Instance Attribute Details

#format_leaderObject

Returns the value of attribute format_leader.



67
68
69
# File 'lib/stringformat.rb', line 67

def format_leader
  @format_leader
end

Instance Method Details

#add_format(spec, &block) ⇒ Object

Takes a spec and a block to process.

“Specs” are one character strings that get transformed into a standard printf()-style format string. The “spec” actually gets used as a combination of the format_leader (usually “%”), any following numeric-like values, and the spec. f.e., the spec “s” would match “%s”, or “%03s” or “%1.3s”.

The block (or in the case of Format.new, the proc) takes two explicit arguments. First, the item that is to be formatted, and second is the numeric-like portion of the format, to be utilized by the callback during processing. The return value (last value evaluated) will be used as the replacement for the format string.

If the block does not take any arguments, this format does not take any arguments and it will be skipped in the argument list.

Please see the top-level documentation for the Format class for examples.



108
109
110
# File 'lib/stringformat.rb', line 108

def add_format(spec, &block)
    @format_table[spec] = block    
end

#del_format(spec) ⇒ Object

Removes a format, given a spec.



113
114
115
# File 'lib/stringformat.rb', line 113

def del_format(spec)
    @format_table.delete spec
end

#format(arg) ⇒ Object Also known as: %

Processes the format and returns a string result. Items passed to this call will correspond to the formats in order from left to right in the string.

An improperly formatted string (one that is passed too many or too little required arguments for what is expected) will raise a StringFormat::FormatError exception.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/stringformat.rb', line 123

def format(arg)
    arg = [arg] unless arg.kind_of? Array

    if arg == [nil]
        arg = []
    end

    count = 0

    new_string = self.dup
    scan(/#{Regexp.quote(@format_leader)}[\d.]*\w/).each do |format|
        tabled_format = format.sub(/^#{Regexp.quote(@format_leader)}[\d.]*/, '')
        unless @format_table[tabled_format]
            raise FormatError, "Invalid format passed in format string"
        end

        num = nil

        if matches = /([\d.]+)/.match(format)
            num = matches[1]
        end

        proc_args = []
        if @format_table[tabled_format].arity == 2
            proc_args = [arg[count], num]
            count += 1
        end

        new_string.sub!(/#{Regexp.quote(format)}/, @format_table[tabled_format].call(*proc_args).to_s)
    end

    if arg.length != count
        raise FormatError, "Not enough formats: #{count} processed when #{arg.length} arguments were attempted"
    end

    return new_string
end

#new_string(s = "") ⇒ Object Also known as: clone

Factory method for producing new strings. Strings will be of class Format and contain all the existing Format definitions at the time this is called.

StringFormat#clone is an alias for this method.



83
84
85
86
87
# File 'lib/stringformat.rb', line 83

def new_string(s="")
    retval = self.dup
    retval.replace(s)
    return retval
end