format_engine 0.7.0 → 0.7.1
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 +69 -14
- data/lib/format_engine/attr_formatter.rb +3 -1
- data/lib/format_engine/attr_parser.rb +3 -0
- data/lib/format_engine/engine.rb +7 -0
- data/lib/format_engine/format_spec.rb +1 -1
- data/lib/format_engine/format_spec/parse_regex.rb +10 -9
- data/lib/format_engine/version.rb +1 -1
- data/mocks/demo/demo_format.rb +4 -1
- data/mocks/demo/demo_parse.rb +13 -5
- data/tests/format_engine_tests.rb +20 -0
- data/tests/parser_engine_tests.rb +14 -0
- 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: bbc14c2d44ed9942c2648f3e96f2599f2328e5fe
|
4
|
+
data.tar.gz: 962a267e81193093a7ba295784dc123154a0f361
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d4c624e4d34c28a8c2e9bebcbb8960b1a173c5b2c6bc7e72bb7aa7b92ca6b6f40939e044bd16fd994b13198432fa7627992bfa7d8694992c01f86f35573fa56
|
7
|
+
data.tar.gz: 484a63a6acb302edc40f3f9c7240ec087c0f518989994249fad1b4776c20a5fe5994bd80dd69702f21ae490b06a323114a5d7b3186f95ef21bc745af9ccede3a
|
data/README.md
CHANGED
@@ -21,13 +21,67 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
-
In general
|
25
|
-
|
26
|
-
|
24
|
+
In general the format engine allows for the easy creation of formatters and
|
25
|
+
parsers. This is done using the attr_formatter and attr_parser methods that
|
26
|
+
work in a manner analogous to attr_reader etc for creating access to instance
|
27
|
+
data.
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
#### attr_formatter
|
30
|
+
|
31
|
+
Creates a data formatting facility for the specified class.
|
32
|
+
|
33
|
+
_Prerequisites_
|
34
|
+
<br>The class must 'extend FormatEngine::AttrFormatter'
|
35
|
+
|
36
|
+
_Arguments_
|
37
|
+
* method_symbol - the name of the formatter instance method created by this
|
38
|
+
method
|
39
|
+
* library - a hash mapping specifications to actions (lambda blocks)
|
40
|
+
|
41
|
+
_Returns_
|
42
|
+
<br>The formatting engine created for the formatter.
|
43
|
+
|
44
|
+
_The created instance method_
|
45
|
+
<br>This method creates an instance method that provides formatted text from
|
46
|
+
an object. This takes the form:
|
47
|
+
|
48
|
+
an_object.method_name(format_string) -> a_formatted_string
|
49
|
+
|
50
|
+
#### attr_parse
|
51
|
+
|
52
|
+
Creates a data parsing facility for the specified class.
|
53
|
+
|
54
|
+
_Prerequisites_
|
55
|
+
<br>The class must 'extend FormatEngine::AttrParser'
|
56
|
+
|
57
|
+
_Arguments_
|
58
|
+
* method_symbol - the name of the parser class method created by this method.
|
59
|
+
* library - a hash mapping specifications to actions (lambda blocks)
|
60
|
+
|
61
|
+
_Returns_
|
62
|
+
<br>The formatting engine created for the parser.
|
63
|
+
|
64
|
+
_The created class method_
|
65
|
+
<br>This method creates an class method that parses formatted text into a new
|
66
|
+
instance of the class. This takes the form:
|
67
|
+
|
68
|
+
AClass.method_name(input_string, format_string) -> an_object
|
69
|
+
|
70
|
+
_Extras_
|
71
|
+
<br>After the parsing method is completed, the unparsed attribute of the parser
|
72
|
+
engine contains the un-processed portion of the input string. If no parsing
|
73
|
+
has been performed, this is an empty string.
|
74
|
+
|
75
|
+
#### Special entries
|
76
|
+
The library has two special entries keyed by symbols instead of strings.
|
77
|
+
These are
|
78
|
+
|
79
|
+
* :before - references a block that is executed before the formatting or
|
80
|
+
parsing process starts.
|
81
|
+
* :after - references a block that is executed after the formatting or
|
82
|
+
parsing process finishes.
|
83
|
+
|
84
|
+
By default, both of these entries take no action.
|
31
85
|
|
32
86
|
### Example
|
33
87
|
The following example is found in the mocks folder:
|
@@ -92,16 +146,17 @@ The parsing of format specification strings is based on the following regular
|
|
92
146
|
expression. This expression is applied repeatedly until all the specifications
|
93
147
|
have been extracted from the input string.
|
94
148
|
|
95
|
-
|
96
|
-
|
149
|
+
PARSE_REGEX =
|
150
|
+
%r{(?<lead> (^|(?<=[^\\]))%){0}
|
151
|
+
(?<flags> [~@#$^&*=?_<>|!]*){0}
|
97
152
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
153
|
+
(?<var> \g<lead>\g<flags>[-+]?(\d+(\.\d+)?)?[a-zA-Z]){0}
|
154
|
+
(?<set> \g<lead>\g<flags>(\d+(,\d+)?)?\[([^\]\\]|\\.)+\]){0}
|
155
|
+
(?<rgx> \g<lead>\g<flags>\/([^\\ \/]|\\.)*\/([imx]*)){0}
|
156
|
+
(?<per> \g<lead>%){0}
|
102
157
|
|
103
|
-
|
104
|
-
|
158
|
+
\g<var> | \g<set> | \g<rgx> | \g<per>
|
159
|
+
}x
|
105
160
|
|
106
161
|
### Var
|
107
162
|
A format specification of the classical form:
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module FormatEngine
|
3
2
|
|
4
3
|
# This module adds the \attr_formatter extension to a class.
|
@@ -16,6 +15,8 @@ module FormatEngine
|
|
16
15
|
#* spec_str - A format specification string with %x etc qualifiers.
|
17
16
|
#<br>Meta-method Returns
|
18
17
|
#* A formatted string
|
18
|
+
#<br>Returns
|
19
|
+
#* The format engine used by this method.
|
19
20
|
def attr_formatter(method, library)
|
20
21
|
engine = Engine.new(library)
|
21
22
|
|
@@ -24,6 +25,7 @@ module FormatEngine
|
|
24
25
|
engine.do_format(self, spec_str)
|
25
26
|
end
|
26
27
|
|
28
|
+
engine
|
27
29
|
end
|
28
30
|
|
29
31
|
end
|
@@ -17,6 +17,8 @@ module FormatEngine
|
|
17
17
|
#* spec_str - A format specification string with %x etc qualifiers.
|
18
18
|
#<br>Meta-method Returns
|
19
19
|
#* An instance of the host class.
|
20
|
+
#<br>Returns
|
21
|
+
#* The format engine used by this method.
|
20
22
|
def attr_parser(method, library)
|
21
23
|
engine = Engine.new(library)
|
22
24
|
|
@@ -25,6 +27,7 @@ module FormatEngine
|
|
25
27
|
engine.do_parse(src, self, spec_str)
|
26
28
|
end
|
27
29
|
|
30
|
+
engine
|
28
31
|
end
|
29
32
|
|
30
33
|
end
|
data/lib/format_engine/engine.rb
CHANGED
@@ -6,10 +6,14 @@ module FormatEngine
|
|
6
6
|
#The parse library
|
7
7
|
attr_reader :library
|
8
8
|
|
9
|
+
#Any un-parsed string data.
|
10
|
+
attr_reader :unparsed
|
11
|
+
|
9
12
|
#Set up base data structures.
|
10
13
|
def initialize(library)
|
11
14
|
@library = library
|
12
15
|
@spec_pool = {}
|
16
|
+
@unparsed = ""
|
13
17
|
|
14
18
|
#Set up defaults for pre and post amble blocks.
|
15
19
|
nop = lambda { }
|
@@ -50,6 +54,9 @@ module FormatEngine
|
|
50
54
|
due_process(spec_info, parse_spec_str) do |format|
|
51
55
|
spec_info.do_parse(format)
|
52
56
|
end
|
57
|
+
|
58
|
+
ensure
|
59
|
+
@unparsed = spec_info.src
|
53
60
|
end
|
54
61
|
|
55
62
|
private
|
@@ -29,7 +29,7 @@ module FormatEngine
|
|
29
29
|
#Scan the format string extracting literals and variables.
|
30
30
|
def scan_spec(fmt_string)
|
31
31
|
until fmt_string.empty?
|
32
|
-
if (match_data =
|
32
|
+
if (match_data = PARSE_REGEX.match(fmt_string))
|
33
33
|
mid = match_data.to_s
|
34
34
|
pre = match_data.pre_match
|
35
35
|
|
@@ -2,15 +2,16 @@ module FormatEngine
|
|
2
2
|
|
3
3
|
#The format string parser.
|
4
4
|
class FormatSpec
|
5
|
-
#The
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
#The regular expression used to parse variable specifications.
|
6
|
+
PARSE_REGEX =
|
7
|
+
%r{(?<lead> (^|(?<=[^\\]))%){0}
|
8
|
+
(?<flags> [~@#$^&*=?_<>|!]*){0}
|
9
|
+
(?<var> \g<lead>\g<flags>[-+]?(\d+(\.\d+)?)?[a-zA-Z]){0}
|
10
|
+
(?<set> \g<lead>\g<flags>(\d+(,\d+)?)?\[([^\]\\]|\\.)+\]){0}
|
11
|
+
(?<rgx> \g<lead>\g<flags>\/([^\\ \/]|\\.)*\/([imx]*)){0}
|
12
|
+
(?<per> \g<lead>%){0}
|
13
|
+
\g<var> | \g<set> | \g<rgx> | \g<per>
|
14
|
+
}x
|
14
15
|
end
|
15
16
|
|
16
17
|
end
|
data/mocks/demo/demo_format.rb
CHANGED
@@ -6,10 +6,13 @@ class Customer
|
|
6
6
|
##
|
7
7
|
#The specification of the formatter method of the demo \Customer class.
|
8
8
|
|
9
|
-
attr_formatter :strfmt,
|
9
|
+
@formatter_engine = attr_formatter :strfmt,
|
10
10
|
{"%a" => lambda {cat "%#{fmt.width_str}d" % src.age },
|
11
11
|
"%f" => lambda {cat "%#{fmt.width_str}s" % src.first_name },
|
12
12
|
"%l" => lambda {cat "%#{fmt.width_str}s" % src.last_name }
|
13
13
|
}
|
14
14
|
|
15
|
+
class << self
|
16
|
+
attr_reader :formatter_engine
|
17
|
+
end
|
15
18
|
end
|
data/mocks/demo/demo_parse.rb
CHANGED
@@ -6,11 +6,19 @@ class Customer
|
|
6
6
|
##
|
7
7
|
#The specification of the parser method of the demo \Customer class.
|
8
8
|
|
9
|
-
attr_parser :strprs,
|
10
|
-
{"%a" => lambda { tmp[:age] = found.to_i if parse(
|
11
|
-
"%f" => lambda { tmp[:fn] = found if parse(
|
12
|
-
"%l" => lambda { tmp[:ln] = found if parse(
|
13
|
-
:after => lambda
|
9
|
+
@parser_engine = attr_parser :strprs,
|
10
|
+
{"%a" => lambda { tmp[:age] = found.to_i if parse(/\d+/) },
|
11
|
+
"%f" => lambda { tmp[:fn] = found.gsub(/_/, ' ') if parse(/\w+/) },
|
12
|
+
"%l" => lambda { tmp[:ln] = found.gsub(/_/, ' ') if parse(/\w+/) },
|
13
|
+
:after => lambda do
|
14
|
+
fail "Customer strprs error, missing field: first name" unless tmp[:fn]
|
15
|
+
fail "Customer strprs error, missing field: last name" unless tmp[:ln]
|
16
|
+
fail "Customer strprs error, missing field: age" unless tmp[:age]
|
17
|
+
set dst.new(tmp[:fn], tmp[:ln], tmp[:age])
|
18
|
+
end
|
14
19
|
}
|
15
20
|
|
21
|
+
class << self
|
22
|
+
attr_reader :parser_engine
|
23
|
+
end
|
16
24
|
end
|
@@ -11,6 +11,11 @@ class FormatEngineTester < Minitest::Test
|
|
11
11
|
#Track mini-test progress.
|
12
12
|
include MinitestVisible
|
13
13
|
|
14
|
+
def test_that_engines_are_returned
|
15
|
+
assert_equal(FormatEngine::Engine, Customer.formatter_engine.class)
|
16
|
+
assert_equal(FormatEngine::Engine, Customer.parser_engine.class)
|
17
|
+
end
|
18
|
+
|
14
19
|
def test_basic_formatting
|
15
20
|
cust = Customer.new("Jane", "Doe", 21)
|
16
21
|
|
@@ -26,4 +31,19 @@ class FormatEngineTester < Minitest::Test
|
|
26
31
|
assert_equal(21, cust.age)
|
27
32
|
end
|
28
33
|
|
34
|
+
def test_some_fancy_footwork
|
35
|
+
cust = Customer.strprs("Wernher, von_Braun 104", "%f, %l %a")
|
36
|
+
|
37
|
+
assert_equal(Customer, cust.class)
|
38
|
+
assert_equal("Wernher", cust.first_name)
|
39
|
+
assert_equal("von Braun", cust.last_name)
|
40
|
+
assert_equal(104, cust.age)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_for_missing_data_detection
|
44
|
+
assert_raises { Customer.strprs("Jane, Doe twenty", "%f, %l %a") }
|
45
|
+
assert_raises { Customer.strprs("Jane", "%f, %l %a") }
|
46
|
+
assert_raises { Customer.strprs("Jane, 34", "%f, %a") }
|
47
|
+
end
|
48
|
+
|
29
49
|
end
|
@@ -167,4 +167,18 @@ class ParserTester < Minitest::Test
|
|
167
167
|
|
168
168
|
end
|
169
169
|
|
170
|
+
def test_for_the_unparsed
|
171
|
+
engine = make_parser
|
172
|
+
assert_equal("", engine.unparsed)
|
173
|
+
|
174
|
+
spec = "%f, %l %a"
|
175
|
+
result = engine.do_parse("Squidly, Jones 55 And much more!", TestPerson, spec)
|
176
|
+
|
177
|
+
assert_equal(TestPerson, result.class)
|
178
|
+
assert_equal("Squidly", result.first_name)
|
179
|
+
assert_equal("Jones", result.last_name)
|
180
|
+
assert_equal(" And much more!", engine.unparsed)
|
181
|
+
|
182
|
+
end
|
183
|
+
|
170
184
|
end
|
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.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Camilleri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|