format_engine 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +86 -1
- data/lib/format_engine/attr_formatter.rb +1 -3
- data/lib/format_engine/attr_parser.rb +1 -3
- data/lib/format_engine/engine.rb +27 -19
- data/lib/format_engine/version.rb +1 -1
- data/tests/formatter_engine_tests.rb +12 -2
- data/tests/parser_engine_tests.rb +7 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53a90dc85e96a48d8f1b469ef5749f63102a4230
|
4
|
+
data.tar.gz: 6555ef6261b11cd7feb5fe996b3e5143d593271b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bd665882c88cdb9ed4acb2e6bed688a3b69585630a74425e2fc14e15a098ebb36899dd609d1c5680ffcb89a68c61390ee808dbfb4535837624f4945fa26c636
|
7
|
+
data.tar.gz: a726f4166591fe0683275b35eec562e4d4f9baadbdbe8f14c41e780736add9b38922941e4efedce6ffcc2e853fd3cec9bb5a1b5398d7d0fe32a21e72d88221eb
|
data/README.md
CHANGED
@@ -21,10 +21,22 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
+
In general formatters and parsers are defined using the attr_formatter
|
25
|
+
and attr_parser methods. Both of these methods accept a symbol and a hash of
|
26
|
+
strings (plus a few special symbols) that point to blocks (that take no arguments).
|
27
|
+
|
28
|
+
The symbol is the name of a method that is created. The hash forms a library
|
29
|
+
of supported formats. Special hash keys are the symbols :before (that is run
|
30
|
+
before all other operations) and :after (that is run after all other operations)
|
31
|
+
|
32
|
+
### Example
|
33
|
+
The following example is found in the mocks folder:
|
34
|
+
|
24
35
|
```ruby
|
25
36
|
require 'format_engine'
|
26
37
|
|
27
38
|
#A demo class for the format_engine gem.
|
39
|
+
|
28
40
|
class Customer
|
29
41
|
extend FormatEngine::AttrFormatter
|
30
42
|
extend FormatEngine::AttrParser
|
@@ -35,10 +47,12 @@ class Customer
|
|
35
47
|
#Demo customer last name
|
36
48
|
attr_reader :last_name
|
37
49
|
|
50
|
+
#Demo defn of the strfmt method for formatted string output!
|
38
51
|
attr_formatter :strfmt,
|
39
52
|
{"%f" => lambda {cat src.first_name.ljust(fmt.width) },
|
40
53
|
"%l" => lambda {cat src.last_name.ljust(fmt.width) } }
|
41
54
|
|
55
|
+
#Demo defn of the strprs method for formatted string input!
|
42
56
|
attr_parser :strprs,
|
43
57
|
{"%f" => lambda { hsh[:fn] = found if parse(/(\w)+/ ) },
|
44
58
|
"%l" => lambda { hsh[:ln] = found if parse(/(\w)+/ ) },
|
@@ -63,6 +77,77 @@ agent = Customer.strprs(in_str, "%f, %l")
|
|
63
77
|
#Etc, etc, etc ...
|
64
78
|
|
65
79
|
```
|
80
|
+
## Format Specification
|
81
|
+
|
82
|
+
Format String Specification Syntax (BNF):
|
83
|
+
|
84
|
+
* spec = { text | item }+
|
85
|
+
* item = "%" {flag}* {parm {"." parm}?}? {command}
|
86
|
+
* flag = { "~" | "@" | "#" | "&" | "^" |
|
87
|
+
"&" | "*" | "-" | "+" | "=" |
|
88
|
+
"?" | "_" | "<" | ">" | "\\" |
|
89
|
+
"/" | "." | "," | "|" | "!" }
|
90
|
+
* parm = { "0" .. "9" }+
|
91
|
+
* command = { "a" .. "z" | "A" .. "Z" }
|
92
|
+
|
93
|
+
|
94
|
+
###Sample:
|
95
|
+
|
96
|
+
The format specification "Elapsed = %*02H:%M:%5.2S!"
|
97
|
+
creates the following format specification array:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
[Literal("Elapsed = "),
|
101
|
+
Variable("%*H", ["02"]),
|
102
|
+
Literal("H"),
|
103
|
+
Variable("%M", nil).
|
104
|
+
Literal(":"),
|
105
|
+
Variable("%S", ["5", "2"]),
|
106
|
+
Literal("!")]
|
107
|
+
```
|
108
|
+
Where literals are processed as themselves and variables are executed by looking
|
109
|
+
up the format string in the library and executing the corresponding block.
|
110
|
+
|
111
|
+
**Note:** If a format string does not correspond to an entry in the library,
|
112
|
+
an exception occurs.
|
113
|
+
|
114
|
+
## Formatting / Parsing Blocks
|
115
|
+
|
116
|
+
In the context of a formatting / parsing block, the
|
117
|
+
"self" of that block is an instance of SpecInfo. The
|
118
|
+
components of that object are:
|
119
|
+
|
120
|
+
###When Formatting:
|
121
|
+
Attributes:
|
122
|
+
* src - The object that is the source of the data (RO).
|
123
|
+
* dst - A string that receives the formatted output (RO).
|
124
|
+
* fmt - The format specification currently being processed (RW).
|
125
|
+
* engine - The formatting engine. Mostly for access to the library (RO).
|
126
|
+
* hsh - A utility hash so that the formatting process can retain state (RO).
|
127
|
+
|
128
|
+
Methods
|
129
|
+
* cat - Append the string that follows to the formatted output. This is
|
130
|
+
equivalent to dst << "string"
|
131
|
+
|
132
|
+
###When Parsing:
|
133
|
+
Attributes:
|
134
|
+
* src - A string that is the source of formatted input (RO).
|
135
|
+
* dst - The class of the object being created (RO).
|
136
|
+
* fmt - The parse specification currently being processed (RW).
|
137
|
+
* engine - The parsing engine. Mostly for access to the library (RO).
|
138
|
+
* hsh - A utility hash so that the parsing process can retain state RO.
|
139
|
+
|
140
|
+
Methods
|
141
|
+
* set - Set the return value of the parsing operation to the value that follows.
|
142
|
+
* parse - Look for the string or regex parm that follows. Return the data found or nil.
|
143
|
+
* parse! - Like parse but raises an exception (with optional msg) if not found.
|
144
|
+
* found? - Did the last parse succeed?
|
145
|
+
* found - The text found by the last parse (or parse!) operation.
|
146
|
+
|
147
|
+
###Format Specifier Attributes
|
148
|
+
The format specifier (accessed as fmt above) has the following attributes:
|
149
|
+
* width - The width parameter or 0 if not specified.
|
150
|
+
* prec - The precision parameter or 0 if not specified.
|
66
151
|
|
67
152
|
## Philosophy
|
68
153
|
|
@@ -70,7 +155,7 @@ When designing this gem, a concerted effort has been applied to keeping it as
|
|
70
155
|
simple as possible. To this end, many subtle programming techniques have been
|
71
156
|
avoided in favor of simpler, more obvious approaches. This is based on the
|
72
157
|
observation that I don't trust code that I don't understand and I avoid code
|
73
|
-
I don't trust.
|
158
|
+
that I don't trust.
|
74
159
|
|
75
160
|
Feedback on the convenience/clarity balance as well as any other topics are
|
76
161
|
most welcomed.
|
@@ -21,9 +21,7 @@ module FormatEngine
|
|
21
21
|
engine = Engine.new(library)
|
22
22
|
|
23
23
|
define_singleton_method(method) do |src, spec_str|
|
24
|
-
|
25
|
-
|
26
|
-
engine.do_parse(src, self, spec)
|
24
|
+
engine.do_parse(src, self, spec_str)
|
27
25
|
end
|
28
26
|
|
29
27
|
end
|
data/lib/format_engine/engine.rb
CHANGED
@@ -18,40 +18,48 @@ module FormatEngine
|
|
18
18
|
@lib[index]
|
19
19
|
end
|
20
20
|
|
21
|
+
# Set an entry in the library
|
22
|
+
def []=(index, value)
|
23
|
+
@lib[index] = value
|
24
|
+
end
|
25
|
+
|
21
26
|
#Do the actual work of building the formatted output.
|
22
27
|
#<br>Parameters
|
23
28
|
#* src - The source object being formatted.
|
24
|
-
#*
|
25
|
-
def do_format(src,
|
26
|
-
|
29
|
+
#* format_spec_str - The format specification string.
|
30
|
+
def do_format(src, format_spec_str)
|
31
|
+
spec_info = SpecInfo.new(src, "", nil, self, {})
|
32
|
+
|
33
|
+
due_process(spec_info, format_spec_str) do |fmt|
|
34
|
+
fmt.do_format(spec_info)
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
#Do the actual work of parsing the formatted input.
|
30
39
|
#<br>Parameters
|
31
40
|
#* src - The source string being parsed.
|
32
41
|
#* dst - The class of the object being created.
|
33
|
-
#*
|
34
|
-
def do_parse(
|
35
|
-
|
42
|
+
#* parse_spec_str - The format specification string.
|
43
|
+
def do_parse(src, dst, parse_spec_str)
|
44
|
+
spec_info = SpecInfo.new(src, dst, nil, self, {})
|
45
|
+
|
46
|
+
due_process(spec_info, parse_spec_str) do |fmt|
|
47
|
+
fmt.do_parse(spec_info)
|
48
|
+
end
|
36
49
|
end
|
37
50
|
|
38
51
|
#Do the actual work of parsing the formatted input.
|
39
52
|
#<br>Parameters
|
40
|
-
#*
|
41
|
-
#*
|
42
|
-
#*
|
43
|
-
|
44
|
-
|
45
|
-
#* :reek:LongParameterList
|
46
|
-
def due_process(src, dst, format_spec, sym)
|
47
|
-
spec_info = SpecInfo.new(src, dst, nil, self, {})
|
48
|
-
spec_info.instance_exec(&self[:before])
|
49
|
-
|
50
|
-
format_spec.validate(self).specs.each do |fmt|
|
51
|
-
fmt.send(sym, spec_info)
|
52
|
-
end
|
53
|
+
#* spec_info - The state of the process.
|
54
|
+
#* spec_str - The format specification string.
|
55
|
+
#* block - A code block performed for each format specification.
|
56
|
+
def due_process(spec_info, spec_str, &block)
|
57
|
+
spec = FormatSpec.get_spec(spec_str).validate(self)
|
53
58
|
|
59
|
+
spec_info.instance_exec(&self[:before])
|
60
|
+
spec.specs.each(&block)
|
54
61
|
spec_info.instance_exec(&self[:after])
|
62
|
+
|
55
63
|
spec_info.dst
|
56
64
|
end
|
57
65
|
|
@@ -28,7 +28,7 @@ class FormatterTester < Minitest::Test
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def make_spec(str)
|
31
|
-
|
31
|
+
str
|
32
32
|
end
|
33
33
|
|
34
34
|
def make_all(str)
|
@@ -60,7 +60,7 @@ class FormatterTester < Minitest::Test
|
|
60
60
|
:before => lambda {dst << "((" },
|
61
61
|
:after => lambda {dst << "))" })
|
62
62
|
|
63
|
-
spec =
|
63
|
+
spec = "Test"
|
64
64
|
assert_equal("((Test))", engine.do_format(nil, spec))
|
65
65
|
end
|
66
66
|
|
@@ -68,4 +68,14 @@ class FormatterTester < Minitest::Test
|
|
68
68
|
engine, obj, spec = make_all("Name = %f %j")
|
69
69
|
assert_raises(RuntimeError) { engine.do_format(obj, spec) }
|
70
70
|
end
|
71
|
+
|
72
|
+
def test_that_it_validates_before_before
|
73
|
+
engine, obj, spec = make_all("Name = %f %j")
|
74
|
+
test = 1
|
75
|
+
engine[:before] = lambda { test = 2 }
|
76
|
+
|
77
|
+
assert_raises(RuntimeError) { engine.do_format(obj, spec) }
|
78
|
+
assert_equal(1, test)
|
79
|
+
end
|
80
|
+
|
71
81
|
end
|
@@ -29,7 +29,7 @@ class ParserTester < Minitest::Test
|
|
29
29
|
|
30
30
|
def test_that_it_can_parse
|
31
31
|
engine = make_parser
|
32
|
-
spec =
|
32
|
+
spec = "%f, %l"
|
33
33
|
result = engine.do_parse("Squidly, Jones", TestPerson, spec)
|
34
34
|
|
35
35
|
assert_equal(TestPerson, result.class)
|
@@ -39,7 +39,7 @@ class ParserTester < Minitest::Test
|
|
39
39
|
|
40
40
|
def test_that_it_can_parse_loudly
|
41
41
|
engine = make_parser
|
42
|
-
spec =
|
42
|
+
spec = "%F, %L"
|
43
43
|
result = engine.do_parse("Squidly, Jones", TestPerson, spec)
|
44
44
|
|
45
45
|
assert_equal(TestPerson, result.class)
|
@@ -49,7 +49,7 @@ class ParserTester < Minitest::Test
|
|
49
49
|
|
50
50
|
def test_that_it_can_fix_shouting
|
51
51
|
engine = make_parser
|
52
|
-
spec =
|
52
|
+
spec = "%-F, %-L"
|
53
53
|
result = engine.do_parse("SQUIDLY, JONES", TestPerson, spec)
|
54
54
|
|
55
55
|
assert_equal(TestPerson, result.class)
|
@@ -59,7 +59,7 @@ class ParserTester < Minitest::Test
|
|
59
59
|
|
60
60
|
def test_that_it_can_flex_parse
|
61
61
|
engine = make_parser
|
62
|
-
spec =
|
62
|
+
spec = "%f%,s%l"
|
63
63
|
result = engine.do_parse("Squidly, Jones", TestPerson, spec)
|
64
64
|
|
65
65
|
assert_equal(TestPerson, result.class)
|
@@ -69,7 +69,7 @@ class ParserTester < Minitest::Test
|
|
69
69
|
|
70
70
|
def test_that_it_can_tab_parse
|
71
71
|
engine = make_parser
|
72
|
-
spec =
|
72
|
+
spec = "%f%t%l"
|
73
73
|
result = engine.do_parse("Squidly\tJones", TestPerson, spec)
|
74
74
|
|
75
75
|
assert_equal(TestPerson, result.class)
|
@@ -79,13 +79,13 @@ class ParserTester < Minitest::Test
|
|
79
79
|
|
80
80
|
def test_that_it_can_detect_errors
|
81
81
|
engine = make_parser
|
82
|
-
spec =
|
82
|
+
spec = "%f, %l"
|
83
83
|
|
84
84
|
assert_raises(RuntimeError) do
|
85
85
|
engine.do_parse("Squidly Jones", TestPerson, spec)
|
86
86
|
end
|
87
87
|
|
88
|
-
spec =
|
88
|
+
spec = "%f%!t%l"
|
89
89
|
|
90
90
|
assert_raises(RuntimeError) do
|
91
91
|
engine.do_parse("Squidly Jones", TestPerson, spec)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: format_engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Camilleri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|