stringformat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2007 Erik Hollensbe
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ * Neither the name of the NGSLib nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,164 @@
1
+ #
2
+ # StringFormat: A string format library that's programmable.
3
+ #
4
+ # Synopsis:
5
+ #
6
+ # # up-front interface
7
+ # f = StringFormat.new(
8
+ # "d" => proc { |item, num| num + ' ' + item } # %0.2d
9
+ # "s" => proc { |item, num| item } # %s
10
+ # )
11
+ #
12
+ # s = f.new_string "my_string %s"
13
+ #
14
+ # # StringFormat is just a subclass of String, so this works:
15
+ #
16
+ # s % "hello there" # => "my_string hello there"
17
+ #
18
+ # # something more complex (using base-class String methods):
19
+ #
20
+ # s[s.length - 2 .. s.length - 1] % "something new" # => "something new"
21
+ #
22
+ # # add iteratively -- works with generated Format#new_string objects as well
23
+ # f.add_format("f") do |item, num|
24
+ # num + ' ' + item
25
+ # end
26
+ #
27
+ # f.del_format("d")
28
+ #
29
+ # # add a format that does not require an argument:
30
+ # f.add_format("e") do
31
+ # Date.new.strftime("%s")
32
+ # end
33
+ #
34
+ # # and use it like such:
35
+ #
36
+ # s = f.clone("string %e %f")
37
+ # s % [1.2] => "string 12345667787 1.2"
38
+ # s = f.clone("string %e")
39
+ # s % nil => "string 12345667787"
40
+ #
41
+ # # these also work on the string objects themselves, so you can add on for specific strings:
42
+ #
43
+ # s.add_format("s") do |item, num|
44
+ # "monkeys around"
45
+ # end
46
+ #
47
+ # s % "foobar" # => "my_string monkeys around"
48
+ #
49
+ # An improperly formatted string (one that is passed too many or too little
50
+ # arguments for what is expected) will raise a StringFormat::FormatError
51
+ # exception.
52
+ #
53
+ # Author:: Erik Hollensbe <erik@hollensbe.org>
54
+ #--
55
+ # TODO LIST
56
+ #
57
+ # Spec conflict checking
58
+ #++
59
+
60
+ class StringFormat < String
61
+
62
+ VERSION = "0.0.1"
63
+
64
+ class FormatError < Exception
65
+ end
66
+
67
+ attr_accessor :format_leader
68
+
69
+ # takes a listing of specifications and procs. For a description of how to
70
+ # define formats, see Format#add_format.
71
+ def initialize(*args)
72
+ @format_table = args[0] || { }
73
+ @format_table.to_hash unless @format_table.respond_to? :keys
74
+ @format_leader = "%"
75
+
76
+ super ""
77
+ end
78
+
79
+ # Factory method for producing new strings. Strings will be of class Format
80
+ # and contain all the existing Format definitions at the time this is called.
81
+ #
82
+ # StringFormat#clone is an alias for this method.
83
+ def new_string(s="")
84
+ retval = self.dup
85
+ retval.replace(s)
86
+ return retval
87
+ end
88
+
89
+ # Takes a spec and a block to process.
90
+ #
91
+ # "Specs" are one character strings that get transformed into a standard
92
+ # printf()-style format string. The "spec" actually gets used as a
93
+ # combination of the format_leader (usually "%"), any following
94
+ # numeric-like values, and the spec. f.e., the spec "s" would match "%s",
95
+ # or "%03s" or "%1.3s".
96
+ #
97
+ # The block (or in the case of Format.new, the proc) takes two explicit
98
+ # arguments. First, the item that is to be formatted, and second is the
99
+ # numeric-like portion of the format, to be utilized by the callback during
100
+ # processing. The return value (last value evaluated) will be used as the
101
+ # replacement for the format string.
102
+ #
103
+ # If the block does not take any arguments, this format does not take any
104
+ # arguments and it will be skipped in the argument list.
105
+ #
106
+ # Please see the top-level documentation for the Format class for examples.
107
+ #
108
+ def add_format(spec, &block)
109
+ @format_table[spec] = block
110
+ end
111
+
112
+ # Removes a format, given a spec.
113
+ def del_format(spec)
114
+ @format_table.delete spec
115
+ end
116
+
117
+ # Processes the format and returns a string result. Items passed to this call will
118
+ # correspond to the formats in order from left to right in the string.
119
+ #
120
+ # An improperly formatted string (one that is passed too many or too
121
+ # little required arguments for what is expected) will raise a
122
+ # StringFormat::FormatError exception.
123
+ def format(arg)
124
+ arg = [arg] unless arg.kind_of? Array
125
+
126
+ if arg == [nil]
127
+ arg = []
128
+ end
129
+
130
+ count = 0
131
+
132
+ new_string = self.dup
133
+ scan(/#{Regexp.quote(@format_leader)}[\d.]*\w/).each do |format|
134
+ tabled_format = format.sub(/^#{Regexp.quote(@format_leader)}[\d.]*/, '')
135
+ unless @format_table[tabled_format]
136
+ raise FormatError, "Invalid format passed in format string"
137
+ end
138
+
139
+ num = nil
140
+
141
+ if matches = /([\d.]+)/.match(format)
142
+ num = matches[1]
143
+ end
144
+
145
+ proc_args = []
146
+ if @format_table[tabled_format].arity == 2
147
+ proc_args = [arg[count], num]
148
+ count += 1
149
+ end
150
+
151
+ new_string.sub!(/#{Regexp.quote(format)}/, @format_table[tabled_format].call(*proc_args).to_s)
152
+ end
153
+
154
+ if arg.length != count
155
+ raise FormatError, "Not enough formats: #{count} processed when #{arg.length} arguments were attempted"
156
+ end
157
+
158
+ return new_string
159
+ end
160
+
161
+ alias :clone :new_string
162
+ alias :% :format
163
+ alias :string= :replace
164
+ end
@@ -0,0 +1,89 @@
1
+ require 'test/unit'
2
+ require 'stringformat'
3
+ require 'date'
4
+ require 'time'
5
+
6
+ class StringFormatTest < Test::Unit::TestCase
7
+
8
+ # test a basic "%s" style stringformat.
9
+ def test_01_basic_format
10
+ f = StringFormat.new(
11
+ "s" => proc do |item, num|
12
+ if num == num.to_i
13
+ item[0..num.to_i - 1]
14
+ elsif num
15
+ snum = num.to_s
16
+ left, right = snum.split(/\./).collect { |x| x.to_i }
17
+ new_string = ""
18
+
19
+ if left && left > 0
20
+ new_string += item[0..left - 1]
21
+ end
22
+
23
+ if right && right < item.length
24
+ new_string += item[item.length - right..item.length-1]
25
+ end
26
+ new_string
27
+ else
28
+ item
29
+ end
30
+ end
31
+ )
32
+
33
+ s = f.clone("string %s %s")
34
+
35
+ assert_equal(s % %w(asdf asdf2), "string asdf asdf2")
36
+
37
+ s = f.new_string("string %s %s")
38
+
39
+ assert_equal(s % %w(asdf asdf2), "string asdf asdf2")
40
+
41
+ # ensure that the formatted strings are copies and not modified references
42
+ assert_not_equal(s % %w(asdf asdf2), s)
43
+
44
+ # ensure that a lack of enough (or too many) formats raises an error
45
+ assert_raise(StringFormat::FormatError) do
46
+ s % %w(asdf)
47
+ end
48
+
49
+ assert_raise(StringFormat::FormatError) do
50
+ s % %w(asdf asdf adsf)
51
+ end
52
+ end
53
+
54
+ # test if the base class string methods are still working.
55
+ def test_02_string_methods
56
+ f = StringFormat.new()
57
+ s = f.new_string "blah"
58
+
59
+ assert_equal(s, s.to_s)
60
+ assert_equal(s + "foo", "#{s}foo")
61
+ assert_equal(s.sub(/blah/, 'foo'), "foo")
62
+ end
63
+
64
+ # test more esoteric formats.
65
+ def test_03_fancy_formats
66
+ # here's some time formats - test our arity functionality
67
+ f = StringFormat.new(
68
+ 't' => proc do
69
+ Time.new.rfc2822
70
+ end,
71
+ 'e' => proc do
72
+ Date.new.strftime("%s")
73
+ end,
74
+ 's' => proc do |item, num|
75
+ item
76
+ end
77
+ )
78
+
79
+ assert_nothing_raised do
80
+ s = f.clone("epoch %e") % nil
81
+ s = f.clone("epoch %e %s") % ["asdf"]
82
+ end
83
+
84
+ assert_equal(f.clone("epoch %e") % nil, "epoch #{Date.new.strftime('%s')}")
85
+ assert_equal(f.clone("epoch %e %s") % ["asdf"], "epoch #{Date.new.strftime('%s')} asdf")
86
+ assert_equal(f.clone("epoch %e %s %e %s") % %w(asdf asdf2), "epoch #{Date.new.strftime('%s')} asdf #{Date.new.strftime('%s')} asdf2")
87
+ assert_equal(f.clone("rfc2822 %t") % nil, "rfc2822 #{Time.new.rfc2822}")
88
+ end
89
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: stringformat
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-09-07 00:00:00 -07:00
8
+ summary: StringFormat is a string formatter library that's intended to be highly flexible
9
+ require_paths:
10
+ - lib
11
+ email: erik@hollensbe.com
12
+ homepage: http://rubyforge.org/projects/ngslib
13
+ rubyforge_project: ngslib
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Erik Hollensbe
31
+ files:
32
+ - lib/LICENSE
33
+ - lib/stringformat.rb
34
+ - test/tc_stringformat.rb
35
+ test_files: []
36
+
37
+ rdoc_options: []
38
+
39
+ extra_rdoc_files:
40
+ - lib/LICENSE
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ requirements: []
46
+
47
+ dependencies: []
48
+