format_engine 0.0.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.
@@ -0,0 +1,83 @@
1
+ module FormatEngine
2
+
3
+ #A little package of info about the engine's progress.
4
+ #In the context of a formatting / parsing block, the
5
+ #"self" of that block is an instance of SpecInfo.
6
+ #<br>
7
+ #<br>The components of that instance Struct are:
8
+ #<br>
9
+ #<br>When Formatting:
10
+ #* src - The object that is the source of the data.
11
+ #* dst - A string that receives the formatted output.
12
+ #* fmt - The format specification currently being processed.
13
+ #* engine - The formatting engine. Mostly for access to the library.
14
+ #* hsh - A utility hash so that the formatting process can retain state.
15
+ #<br>Methods
16
+ #* cat - Append the string that follows to the formatted output.
17
+ #<br>
18
+ #<br>When Parsing:
19
+ #* src - A string that is the source of formatted input.
20
+ #* dst - The class of the object being created.
21
+ #* fmt - The parse specification currently being processed.
22
+ #* engine - The parsing engine. Mostly for access to the library.
23
+ #* hsh - A utility hash so that the parsing process can retain state.
24
+ #<br>Methods
25
+ #* set - Set the return value of the parsing operation to the value that follows.
26
+ #* parse - Look for the string or regex parm that follows. Return the data found or nil.
27
+ #* parse! - Like parse but raises an exception (with optional msg) if not found.
28
+ #* found? - Did the last parse succeed?
29
+ #* found - The text found by the last parse (or parse!) operation.
30
+ class SpecInfo
31
+
32
+ # General readers
33
+ attr_reader :src, :dst, :engine, :hsh
34
+
35
+ #General accessors
36
+ attr_accessor :fmt
37
+
38
+ # Set up the spec info.
39
+ def initialize(src, dst, fmt, engine, hsh = {})
40
+ @src, @dst, @fmt, @engine, @hsh = src, dst, fmt, engine, hsh
41
+ end
42
+
43
+ # Concatenate onto the formatted output string.
44
+ def cat(str)
45
+ @dst << str
46
+ end
47
+
48
+ # Set the result of this parsing operation.
49
+ def set(obj)
50
+ @dst = obj
51
+ end
52
+
53
+ # Parse the source string for a string or regex
54
+ def parse(tgt)
55
+ @result = src.partition(tgt)
56
+
57
+ if found?
58
+ @src = @result[2]
59
+ @result[1]
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ # Parse the source string for a string or regex or raise error.
66
+ def parse!(tgt, msg = "#{tgt.inspect} not found")
67
+ fail "Parse error: #{msg}" unless parse(tgt)
68
+ found
69
+ end
70
+
71
+ # Was the last parse a success?
72
+ def found?
73
+ @result[0].empty? && !@result[1].empty?
74
+ end
75
+
76
+ # What was found by the last parse?
77
+ def found
78
+ @result[1]
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,5 @@
1
+
2
+ module FormatEngine
3
+ # The version of the format_engine gem.
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,11 @@
1
+ #The format_engine gem top source file.
2
+
3
+ require 'English'
4
+
5
+ require 'format_engine/format_spec'
6
+ require 'format_engine/engine'
7
+ require 'format_engine/spec_info'
8
+ require 'format_engine/attr_formatter'
9
+ require 'format_engine/attr_parser'
10
+
11
+ require 'format_engine/version'
data/mocks/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # FormatEngine - The mocks folder.
2
+
3
+ This is a new idea that is being evaluated. In order to keep code DRY and
4
+ encourage proper care and maintenance of mocks and stubs, this folder
5
+ will contain those mocks and stubs. The idea is that by making them into
6
+ separate entities in their own right, they just might get a little more
7
+ respect.
8
+
9
+ In addition, it may encourage the sharing and increased scrutiny of these
10
+ testing tools and thus improve productivity and quality.
@@ -0,0 +1,13 @@
1
+ #* mocks/demo/demo_formatting.rb - Formatting specifications for the \Customer class.
2
+ class Customer
3
+
4
+ extend FormatEngine::AttrFormatter
5
+
6
+ ##
7
+ #The specification of the formatter method of the demo \Customer class.
8
+
9
+ attr_formatter :strfmt,
10
+ {"%f" => lambda {cat src.first_name.ljust(fmt.width) },
11
+ "%l" => lambda {cat src.last_name.ljust(fmt.width) } }
12
+
13
+ end
@@ -0,0 +1,14 @@
1
+ #* mocks/demo/demo_parse.rb - Parsing specifications for the \Customer class.
2
+ class Customer
3
+
4
+ extend FormatEngine::AttrParser
5
+
6
+ ##
7
+ #The specification of the parser method of the demo \Customer class.
8
+
9
+ attr_parser :strprs,
10
+ {"%f" => lambda { hsh[:fn] = found if parse(/(\w)+/ ) },
11
+ "%l" => lambda { hsh[:ln] = found if parse(/(\w)+/ ) },
12
+ :after => lambda { set dst.new(hsh[:fn], hsh[:ln]) } }
13
+
14
+ end
data/mocks/demo.rb ADDED
@@ -0,0 +1,18 @@
1
+ # A simple class of customer info.
2
+
3
+ require_relative 'demo/demo_format'
4
+ require_relative 'demo/demo_parse'
5
+
6
+ #A demo class for the format_engine gem.
7
+ class Customer
8
+ #Demo customer first name.
9
+ attr_reader :first_name
10
+
11
+ #Demo customer last name
12
+ attr_reader :last_name
13
+
14
+ #Create an instance of the demo customer.
15
+ def initialize(first_name, last_name)
16
+ @first_name, @last_name = first_name, last_name
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+
2
+ # A mock class to test formatting
3
+ class TestPerson
4
+ attr_reader :first_name
5
+ attr_reader :last_name
6
+
7
+ def initialize(first_name, last_name)
8
+ @first_name, @last_name = first_name, last_name
9
+ end
10
+ end
data/reek.txt ADDED
@@ -0,0 +1,2 @@
1
+
2
+ 0 total warnings
@@ -0,0 +1,18 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ class EngineBaseTester < Minitest::Test
7
+
8
+ #Track mini-test progress.
9
+ MinitestVisible.track self, __FILE__
10
+
11
+ def test_that_it_has_a_library
12
+ test = FormatEngine::Engine.new({"%A" => 42})
13
+
14
+ assert_equal(42, test["%A"])
15
+ assert_equal(nil, test["%B"])
16
+ end
17
+
18
+ end
@@ -0,0 +1,29 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ require_relative '../mocks/demo'
7
+
8
+ # A full test of the formatter/parser engine.
9
+ class FormatEngineTester < Minitest::Test
10
+
11
+ #Track mini-test progress.
12
+ MinitestVisible.track self, __FILE__
13
+
14
+ def test_basic_formatting
15
+ cust = Customer.new("Jane", "Doe")
16
+
17
+ assert_equal("Jane, Doe", cust.strfmt("%f, %l"))
18
+ end
19
+
20
+
21
+ def test_basic_parsing
22
+ cust = Customer.strprs("Jane, Doe", "%f, %l")
23
+
24
+ assert_equal(Customer, cust.class)
25
+ assert_equal("Jane", cust.first_name)
26
+ assert_equal("Doe", cust.last_name)
27
+ end
28
+
29
+ end
@@ -0,0 +1,120 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ class FormatSpecTester < Minitest::Test
7
+
8
+ #Track mini-test progress.
9
+ MinitestVisible.track self, __FILE__
10
+
11
+ def test_that_it_scans_literal_formats
12
+ test = FormatEngine::FormatSpec.get_spec "ABCDEFG!"
13
+ assert_equal(Array, test.specs.class)
14
+ assert_equal(1, test.specs.length)
15
+ assert_equal(FormatEngine::FormatLiteral, test.specs[0].class)
16
+ assert_equal("ABCDEFG!", test.specs[0].literal)
17
+ end
18
+
19
+ def test_that_it_scans_simple_variable_formats
20
+ test = FormatEngine::FormatSpec.get_spec "%A"
21
+ assert_equal(Array, test.specs.class)
22
+ assert_equal(1, test.specs.length)
23
+ assert_equal(FormatEngine::FormatVariable, test.specs[0].class)
24
+ assert_equal("%A", test.specs[0].format)
25
+ assert_equal(nil, test.specs[0].parms)
26
+ end
27
+
28
+ def test_that_it_scans_option_variable_formats
29
+ "~@#&^&*-+=?_<>\\/.,|".each_char do |char|
30
+ test = FormatEngine::FormatSpec.get_spec "%#{char}A"
31
+ assert_equal(Array, test.specs.class)
32
+ assert_equal(1, test.specs.length)
33
+ assert_equal(FormatEngine::FormatVariable, test.specs[0].class)
34
+ assert_equal("%#{char}A", test.specs[0].format)
35
+ end
36
+ end
37
+
38
+ def test_that_it_scans_single_variable_formats
39
+ test = FormatEngine::FormatSpec.get_spec "%123A"
40
+ assert_equal(Array, test.specs.class)
41
+ assert_equal(1, test.specs.length)
42
+ assert_equal(FormatEngine::FormatVariable, test.specs[0].class)
43
+ assert_equal("%A", test.specs[0].format)
44
+
45
+ assert_equal(Array, test.specs[0].parms.class)
46
+ assert_equal(1, test.specs[0].parms.length)
47
+ assert_equal("123", test.specs[0].parms[0])
48
+ end
49
+
50
+ def test_that_it_scans_double_variable_formats
51
+ test = FormatEngine::FormatSpec.get_spec "%123.456A"
52
+ assert_equal(Array, test.specs.class)
53
+ assert_equal(1, test.specs.length)
54
+ assert_equal(FormatEngine::FormatVariable, test.specs[0].class)
55
+ assert_equal("%A", test.specs[0].format)
56
+
57
+ assert_equal(Array, test.specs[0].parms.class)
58
+ assert_equal(2, test.specs[0].parms.length)
59
+ assert_equal("123", test.specs[0].parms[0])
60
+ assert_equal("456", test.specs[0].parms[1])
61
+ end
62
+
63
+ def test_multipart_formats
64
+ test = FormatEngine::FormatSpec.get_spec "T(%+02A:%3B:%4.1C)"
65
+
66
+ assert_equal(Array, test.specs.class)
67
+ assert_equal(7, test.specs.length)
68
+
69
+ assert_equal(FormatEngine::FormatLiteral, test.specs[0].class)
70
+ assert_equal("T(", test.specs[0].literal)
71
+
72
+ assert_equal(FormatEngine::FormatVariable, test.specs[1].class)
73
+ assert_equal("%+A", test.specs[1].format)
74
+ assert_equal(1, test.specs[1].parms.length)
75
+ assert_equal("02", test.specs[1].parms[0])
76
+
77
+ assert_equal(FormatEngine::FormatLiteral, test.specs[2].class)
78
+ assert_equal(":", test.specs[2].literal)
79
+
80
+ assert_equal(FormatEngine::FormatVariable, test.specs[3].class)
81
+ assert_equal("%B", test.specs[3].format)
82
+ assert_equal(1, test.specs[3].parms.length)
83
+ assert_equal("3", test.specs[3].parms[0])
84
+
85
+ assert_equal(FormatEngine::FormatLiteral, test.specs[4].class)
86
+ assert_equal(":", test.specs[4].literal)
87
+
88
+ assert_equal(FormatEngine::FormatVariable, test.specs[5].class)
89
+ assert_equal("%C", test.specs[5].format)
90
+ assert_equal(2, test.specs[5].parms.length)
91
+ assert_equal("4", test.specs[5].parms[0])
92
+ assert_equal("1", test.specs[5].parms[1])
93
+
94
+ assert_equal(FormatEngine::FormatLiteral, test.specs[6].class)
95
+ assert_equal(")", test.specs[6].literal)
96
+ end
97
+
98
+ def test_that_it_validates
99
+ engine = { "%A" => true, "%B" => true }
100
+
101
+ test = FormatEngine::FormatSpec.get_spec "%A and %B"
102
+ assert_equal(test, test.validate(engine))
103
+
104
+ test = FormatEngine::FormatSpec.get_spec "%A and %C"
105
+ assert_raises(RuntimeError) { test.validate(engine) }
106
+ end
107
+
108
+ def test_that_it_caches
109
+ t1 = FormatEngine::FormatSpec.get_spec "%123.456A"
110
+ t2 = FormatEngine::FormatSpec.get_spec "%123.456A"
111
+ assert(t1.object_id == t2.object_id)
112
+
113
+ t3 = FormatEngine::FormatSpec.get_spec "%123.457A"
114
+ assert(t1.object_id != t3.object_id)
115
+
116
+ t4 = FormatEngine::FormatSpec.get_spec "%123.457A"
117
+ assert(t4.object_id == t3.object_id)
118
+ end
119
+
120
+ end
@@ -0,0 +1,71 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ require_relative '../mocks/test_person_mock'
7
+
8
+ # Test the internals of the formatter engine. This is not the normal interface.
9
+ class FormatterTester < Minitest::Test
10
+
11
+ #Track mini-test progress.
12
+ MinitestVisible.track self, __FILE__
13
+
14
+ def make_formatter
15
+ FormatEngine::Engine.new(
16
+ "%f" => lambda {cat src.first_name.ljust(fmt.width) },
17
+ "%-f" => lambda {cat src.first_name.rjust(fmt.width) },
18
+ "%F" => lambda {cat src.first_name.upcase.ljust(fmt.width) },
19
+ "%-F" => lambda {cat src.first_name.upcase.rjust(fmt.width) },
20
+ "%l" => lambda {cat src.last_name.ljust(fmt.width)},
21
+ "%-l" => lambda {cat src.last_name.rjust(fmt.width)},
22
+ "%L" => lambda {cat src.last_name.upcase.ljust(fmt.width) },
23
+ "%-L" => lambda {cat src.last_name.upcase.rjust(fmt.width) })
24
+ end
25
+
26
+ def make_person
27
+ TestPerson.new("Squidly", "Jones")
28
+ end
29
+
30
+ def make_spec(str)
31
+ FormatEngine::FormatSpec.get_spec str
32
+ end
33
+
34
+ def make_all(str)
35
+ [make_formatter, make_person, make_spec(str)]
36
+ end
37
+
38
+ def test_that_it_can_format_normally
39
+ engine, obj, spec = make_all("Name = %f %l")
40
+ assert_equal("Name = Squidly Jones", engine.do_format(obj, spec))
41
+ end
42
+
43
+ def test_that_it_can_format_shouting
44
+ engine, obj, spec = make_all("Name = %F %L")
45
+ assert_equal("Name = SQUIDLY JONES", engine.do_format(obj, spec))
46
+ end
47
+
48
+ def test_that_it_can_format_wider
49
+ engine, obj, spec = make_all("Name = %10f %10l")
50
+ assert_equal("Name = Squidly Jones ", engine.do_format(obj, spec))
51
+ end
52
+
53
+ def test_that_it_can_format_right
54
+ engine, obj, spec = make_all("Name = %-10f %-10l")
55
+ assert_equal("Name = Squidly Jones", engine.do_format(obj, spec))
56
+ end
57
+
58
+ def test_that_it_calls_before_and_after
59
+ engine = FormatEngine::Engine.new(
60
+ :before => lambda {dst << "((" },
61
+ :after => lambda {dst << "))" })
62
+
63
+ spec = FormatEngine::FormatSpec.get_spec "Test"
64
+ assert_equal("((Test))", engine.do_format(nil, spec))
65
+ end
66
+
67
+ def test_that_it_rejects_bad_specs
68
+ engine, obj, spec = make_all("Name = %f %j")
69
+ assert_raises(RuntimeError) { engine.do_format(obj, spec) }
70
+ end
71
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ class LiteralSpecTester < Minitest::Test
7
+
8
+ #Track mini-test progress.
9
+ MinitestVisible.track self, __FILE__
10
+
11
+ def test_that_it_validates_always
12
+ test = FormatEngine::FormatLiteral.new("Test 1 2 3")
13
+ assert_equal(test, test.validate(nil))
14
+ end
15
+
16
+ def test_that_it_formats
17
+ spec_info = FormatEngine::SpecInfo.new(nil, "", nil, nil, {})
18
+ test = FormatEngine::FormatLiteral.new("Test 1 2 3")
19
+ test.do_format(spec_info)
20
+
21
+ assert_equal("Test 1 2 3", spec_info.dst)
22
+ end
23
+ end
@@ -0,0 +1,95 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ require_relative '../mocks/test_person_mock'
7
+
8
+ # Test the internals of the parser engine. This is not the normal interface.
9
+ class ParserTester < Minitest::Test
10
+
11
+ #Track mini-test progress.
12
+ MinitestVisible.track self, __FILE__
13
+
14
+ def make_parser
15
+ FormatEngine::Engine.new(
16
+ "%f" => lambda { hsh[:fn] = found if parse(/(\w)+/ ) },
17
+ "%F" => lambda { hsh[:fn] = found.upcase if parse(/(\w)+/) },
18
+ "%-F" => lambda { hsh[:fn] = found.capitalize if parse(/(\w)+/) },
19
+ "%l" => lambda { hsh[:ln] = found if parse(/(\w)+/ ) },
20
+ "%L" => lambda { hsh[:ln] = found.upcase if parse(/(\w)+/) },
21
+ "%-L" => lambda { hsh[:ln] = found.capitalize if parse(/(\w)+/) },
22
+ "%s" => lambda { parse(/\s+/) },
23
+ "%,s" => lambda { parse(/[,\s]\s*/) },
24
+ "%t" => lambda { parse("\t") },
25
+ "%!t" => lambda { parse!("\t") },
26
+
27
+ :after => lambda { set TestPerson.new(hsh[:fn], hsh[:ln]) })
28
+ end
29
+
30
+ def test_that_it_can_parse
31
+ engine = make_parser
32
+ spec = FormatEngine::FormatSpec.get_spec "%f, %l"
33
+ result = engine.do_parse("Squidly, Jones", TestPerson, spec)
34
+
35
+ assert_equal(TestPerson, result.class)
36
+ assert_equal("Squidly", result.first_name)
37
+ assert_equal("Jones", result.last_name)
38
+ end
39
+
40
+ def test_that_it_can_parse_loudly
41
+ engine = make_parser
42
+ spec = FormatEngine::FormatSpec.get_spec "%F, %L"
43
+ result = engine.do_parse("Squidly, Jones", TestPerson, spec)
44
+
45
+ assert_equal(TestPerson, result.class)
46
+ assert_equal("SQUIDLY", result.first_name)
47
+ assert_equal("JONES", result.last_name)
48
+ end
49
+
50
+ def test_that_it_can_fix_shouting
51
+ engine = make_parser
52
+ spec = FormatEngine::FormatSpec.get_spec "%-F, %-L"
53
+ result = engine.do_parse("SQUIDLY, JONES", TestPerson, spec)
54
+
55
+ assert_equal(TestPerson, result.class)
56
+ assert_equal("Squidly", result.first_name)
57
+ assert_equal("Jones", result.last_name)
58
+ end
59
+
60
+ def test_that_it_can_flex_parse
61
+ engine = make_parser
62
+ spec = FormatEngine::FormatSpec.get_spec "%f%,s%l"
63
+ result = engine.do_parse("Squidly, Jones", TestPerson, spec)
64
+
65
+ assert_equal(TestPerson, result.class)
66
+ assert_equal("Squidly", result.first_name)
67
+ assert_equal("Jones", result.last_name)
68
+ end
69
+
70
+ def test_that_it_can_tab_parse
71
+ engine = make_parser
72
+ spec = FormatEngine::FormatSpec.get_spec "%f%t%l"
73
+ result = engine.do_parse("Squidly\tJones", TestPerson, spec)
74
+
75
+ assert_equal(TestPerson, result.class)
76
+ assert_equal("Squidly", result.first_name)
77
+ assert_equal("Jones", result.last_name)
78
+ end
79
+
80
+ def test_that_it_can_detect_errors
81
+ engine = make_parser
82
+ spec = FormatEngine::FormatSpec.get_spec "%f, %l"
83
+
84
+ assert_raises(RuntimeError) do
85
+ engine.do_parse("Squidly Jones", TestPerson, spec)
86
+ end
87
+
88
+ spec = FormatEngine::FormatSpec.get_spec "%f%!t%l"
89
+
90
+ assert_raises(RuntimeError) do
91
+ engine.do_parse("Squidly Jones", TestPerson, spec)
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../lib/format_engine'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'minitest_visible'
5
+
6
+ class VariableSpecTester < Minitest::Test
7
+
8
+ #Track mini-test progress.
9
+ MinitestVisible.track self, __FILE__
10
+
11
+ def test_that_it_validates
12
+ engine = { "%A" => true }
13
+
14
+ test = FormatEngine::FormatVariable.new("%A")
15
+ assert_equal(test, test.validate(engine))
16
+
17
+ test = FormatEngine::FormatVariable.new("%B")
18
+ assert_raises(RuntimeError) { test.validate(engine) }
19
+ end
20
+
21
+ def test_the_parms
22
+ test = FormatEngine::FormatVariable.new("%B")
23
+ assert_equal(0, test.width)
24
+ assert_equal(0, test.prec)
25
+
26
+ test = FormatEngine::FormatVariable.new("%10B")
27
+ assert_equal(10, test.width)
28
+ assert_equal(0, test.prec)
29
+
30
+ test = FormatEngine::FormatVariable.new("%10.5B")
31
+ assert_equal(10, test.width)
32
+ assert_equal(5, test.prec)
33
+ end
34
+ end