fixed_width-multibyte 0.2.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.
@@ -0,0 +1,81 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe FixedWidth::Definition do
4
+ before(:each) do
5
+ end
6
+
7
+ describe "when specifying alignment" do
8
+ it "should have an alignment option" do
9
+ d = FixedWidth::Definition.new :align => :right
10
+ d.options[:align].should == :right
11
+ end
12
+
13
+ it "should default to being right aligned" do
14
+ d = FixedWidth::Definition.new
15
+ d.options[:align].should == :right
16
+ end
17
+
18
+ it "should override the default if :align is passed to the section" do
19
+ section = mock('section', :null_object => true)
20
+ FixedWidth::Section.should_receive(:new).with('name', {:align => :left}).and_return(section)
21
+ d = FixedWidth::Definition.new
22
+ d.options[:align].should == :right
23
+ d.section('name', :align => :left) {}
24
+ end
25
+ end
26
+
27
+ describe "when creating a section" do
28
+ before(:each) do
29
+ @d = FixedWidth::Definition.new
30
+ @section = mock('section', :null_object => true)
31
+ end
32
+
33
+ it "should create and yield a new section object" do
34
+ yielded = nil
35
+ @d.section :header do |section|
36
+ yielded = section
37
+ end
38
+ yielded.should be_a(FixedWidth::Section)
39
+ @d.sections.first.should == yielded
40
+ end
41
+
42
+ it "should magically build a section from an unknown method" do
43
+ FixedWidth::Section.should_receive(:new).with(:header, anything()).and_return(@section)
44
+ @d.header {}
45
+ end
46
+
47
+ it "should not create duplicate section names" do
48
+ lambda { @d.section(:header) {} }.should_not raise_error(FixedWidth::DuplicateSectionNameError)
49
+ lambda { @d.section(:header) {} }.should raise_error(FixedWidth::DuplicateSectionNameError, "Duplicate section name: 'header'")
50
+ end
51
+ end
52
+
53
+ describe "when creating a template" do
54
+ before(:each) do
55
+ @d = FixedWidth::Definition.new
56
+ @section = mock('section', :null_object => true)
57
+ end
58
+
59
+ it "should create a new section" do
60
+ FixedWidth::Section.should_receive(:new).with(:row, anything()).and_return(@section)
61
+ @d.template(:row) {}
62
+ end
63
+
64
+ it "should yield the new section" do
65
+ FixedWidth::Section.should_receive(:new).with(:row, anything()).and_return(@section)
66
+ yielded = nil
67
+ @d.template :row do |section|
68
+ yielded = section
69
+ end
70
+ yielded.should == @section
71
+ end
72
+
73
+ it "add a section to the templates collection" do
74
+ @d.should have(0).templates
75
+ @d.template :row do |t|
76
+ t.column :id, 3
77
+ end
78
+ @d.should have(1).templates
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,81 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe FixedWidth do
4
+
5
+ before(:each) do
6
+ @name = :doc
7
+ @options = { :align => :left }
8
+ end
9
+
10
+ describe "when defining a format" do
11
+ before(:each) do
12
+ @definition = mock('definition')
13
+ end
14
+
15
+ it "should create a new definition using the specified name and options" do
16
+ FixedWidth.should_receive(:define).with(@name, @options).and_return(@definition)
17
+ FixedWidth.define(@name , @options)
18
+ end
19
+
20
+ it "should pass the definition to the block" do
21
+ yielded = nil
22
+ FixedWidth.define(@name) do |y|
23
+ yielded = y
24
+ end
25
+ yielded.should be_a( FixedWidth::Definition )
26
+ end
27
+
28
+ it "should add to the internal definition count" do
29
+ FixedWidth.definitions.clear
30
+ FixedWidth.should have(0).definitions
31
+ FixedWidth.define(@name , @options) {}
32
+ FixedWidth.should have(1).definitions
33
+ end
34
+ end
35
+
36
+ describe "when creating file from data" do
37
+ it "should raise an error if the definition name is not found" do
38
+ lambda { FixedWidth.generate(:not_there, {}) }.should raise_error(ArgumentError)
39
+ end
40
+
41
+ it "should output a string" do
42
+ definition = mock('definition')
43
+ generator = mock('generator')
44
+ generator.should_receive(:generate).with({})
45
+ FixedWidth.should_receive(:definition).with(:test).and_return(definition)
46
+ FixedWidth::Generator.should_receive(:new).with(definition).and_return(generator)
47
+ FixedWidth.generate(:test, {})
48
+ end
49
+
50
+ it "should output a file" do
51
+ file = mock('file')
52
+ text = mock('string')
53
+ file.should_receive(:write).with(text)
54
+ FixedWidth.should_receive(:generate).with(:test, {}).and_return(text)
55
+ FixedWidth.write(file, :test, {})
56
+ end
57
+ end
58
+
59
+ describe "when parsing a file" do
60
+ before(:each) do
61
+ @file = mock('file')
62
+ end
63
+
64
+ it "should check the file exists" do
65
+ lambda { FixedWidth.parse(@file, :test, {}) }.should raise_error(ArgumentError)
66
+ end
67
+
68
+ it "should raise an error if the definition name is not found" do
69
+ FixedWidth.definitions.clear
70
+ lambda { FixedWidth.parse(@file, :test, {}) }.should raise_error(ArgumentError)
71
+ end
72
+
73
+ it "should create a parser and call parse" do
74
+ parser = mock("parser", :null_object => true)
75
+ definition = mock('definition')
76
+ FixedWidth.should_receive(:definition).with(:test).and_return(definition)
77
+ FixedWidth::Parser.should_receive(:new).with(definition, @file).and_return(parser)
78
+ FixedWidth.parse(@file, :test)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe FixedWidth::Generator do
4
+ before(:each) do
5
+ @definition = FixedWidth.define :test do |d|
6
+ d.header do |h|
7
+ h.trap { |line| line[0,4] == 'HEAD' }
8
+ h.column :type, 4
9
+ h.column :file_id, 10
10
+ end
11
+ d.body do |b|
12
+ b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ }
13
+ b.column :first, 10
14
+ b.column :last, 10
15
+ end
16
+ d.footer do |f|
17
+ f.trap { |line| line[0,4] == 'FOOT' }
18
+ f.column :type, 4
19
+ f.column :file_id, 10
20
+ end
21
+ end
22
+ @data = {
23
+ :header => [ {:type => "HEAD", :file_id => "1" } ],
24
+ :body => [
25
+ {:first => "Paul", :last => "Hewson" },
26
+ {:first => "Dave", :last => "Evans" }
27
+ ],
28
+ :footer => [ {:type => "FOOT", :file_id => "1" }]
29
+ }
30
+ @generator = FixedWidth::Generator.new(@definition)
31
+ end
32
+
33
+ it "should raise an error if there is no data for a required section" do
34
+ @data.delete :header
35
+ lambda { @generator.generate(@data) }.should raise_error(FixedWidth::RequiredSectionEmptyError, "Required section 'header' was empty.")
36
+ end
37
+
38
+ it "should generate a string" do
39
+ expected = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1"
40
+ @generator.generate(@data).should == expected
41
+ end
42
+
43
+ it "should handle lazy data declaration (no array around single record for a section)" do
44
+ expected = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1"
45
+ @data[:header] = @data[:header].first
46
+ @generator.generate(@data).should == expected
47
+ end
48
+ end
@@ -0,0 +1,110 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe FixedWidth::Parser do
4
+ before(:each) do
5
+ @definition = mock('definition', :sections => [])
6
+ @file = mock("file")
7
+ @parser = FixedWidth::Parser.new(@definition, @file)
8
+ end
9
+
10
+ it "should read in a source file" do
11
+ @file.should_receive(:readlines).and_return(["\n"])
12
+ @parser.parse
13
+ end
14
+
15
+ describe "when parsing sections" do
16
+ before(:each) do
17
+ @definition = FixedWidth.define :test do |d|
18
+ d.header do |h|
19
+ h.trap { |line| line[0,4] == 'HEAD' }
20
+ h.column :type, 4
21
+ h.column :file_id, 10
22
+ end
23
+ d.body do |b|
24
+ b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ }
25
+ b.column :first, 10
26
+ b.column :last, 10
27
+ end
28
+ d.footer do |f|
29
+ f.trap { |line| line[0,4] == 'FOOT' }
30
+ f.column :type, 4
31
+ f.column :file_id, 10
32
+ end
33
+ end
34
+ @parser = FixedWidth::Parser.new(@definition, @file)
35
+ end
36
+
37
+ it "should add lines to the proper sections" do
38
+ @file.should_receive(:readlines).and_return([
39
+ "HEAD 1\n",
40
+ " Paul Hewson\n",
41
+ " Dave Evans\n",
42
+ "FOOT 1\n"
43
+ ])
44
+ expected = {
45
+ :header => [ {:type => "HEAD", :file_id => "1" } ],
46
+ :body => [
47
+ {:first => "Paul", :last => "Hewson" },
48
+ {:first => "Dave", :last => "Evans" }
49
+ ],
50
+ :footer => [ {:type => "FOOT", :file_id => "1" } ]
51
+ }
52
+ result = @parser.parse
53
+ result.should == expected
54
+ end
55
+
56
+ it "should treat singular sections properly" do
57
+ @definition = FixedWidth.define :test do |d|
58
+ d.header(:singular => true) do |h|
59
+ h.trap { |line| line[0,4] == 'HEAD' }
60
+ h.column :type, 4
61
+ h.column :file_id, 10
62
+ end
63
+ d.body do |b|
64
+ b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ }
65
+ b.column :first, 10
66
+ b.column :last, 10
67
+ end
68
+ d.footer(:singular => true) do |f|
69
+ f.trap { |line| line[0,4] == 'FOOT' }
70
+ f.column :type, 4
71
+ f.column :file_id, 10
72
+ end
73
+ end
74
+ @parser = FixedWidth::Parser.new(@definition, @file)
75
+ @file.should_receive(:readlines).and_return([
76
+ "HEAD 1\n",
77
+ " Paul Hewson\n",
78
+ " Dave Evans\n",
79
+ "FOOT 1\n"
80
+ ])
81
+ expected = {
82
+ :header => {:type => "HEAD", :file_id => "1" },
83
+ :body => [
84
+ {:first => "Paul", :last => "Hewson" },
85
+ {:first => "Dave", :last => "Evans" }
86
+ ],
87
+ :footer => {:type => "FOOT", :file_id => "1" }
88
+ }
89
+ result = @parser.parse
90
+ result.should == expected
91
+ end
92
+
93
+ it "should allow optional sections to be skipped" do
94
+ @definition.sections[0].optional = true
95
+ @definition.sections[2].optional = true
96
+ @file.should_receive(:readlines).and_return([
97
+ " Paul Hewson\n"
98
+ ])
99
+ expected = { :body => [ {:first => "Paul", :last => "Hewson" } ] }
100
+ @parser.parse.should == expected
101
+ end
102
+
103
+ it "should raise an error if a required section is not found" do
104
+ @file.should_receive(:readlines).and_return([
105
+ " Ryan Wood\n"
106
+ ])
107
+ lambda { @parser.parse }.should raise_error(FixedWidth::RequiredSectionNotFoundError, "Required section 'header' was not found.")
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,188 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+
4
+ describe FixedWidth::Section do
5
+ before(:each) do
6
+ @section = FixedWidth::Section.new(:body)
7
+ end
8
+
9
+ it "should have no columns after creation" do
10
+ @section.columns.should be_empty
11
+ end
12
+
13
+ describe "when adding columns" do
14
+ it "should build an ordered column list" do
15
+ @section.should have(0).columns
16
+
17
+ col1 = @section.column :id, 10
18
+ col2 = @section.column :name, 30
19
+ col3 = @section.column :state, 2
20
+
21
+ @section.should have(3).columns
22
+ @section.columns[0].should be(col1)
23
+ @section.columns[1].should be(col2)
24
+ @section.columns[2].should be(col3)
25
+ end
26
+
27
+ it "should create spacer columns" do
28
+ @section.should have(0).columns
29
+ @section.spacer(5)
30
+ @section.should have(1).columns
31
+ end
32
+
33
+ it "can should override the alignment of the definition" do
34
+ section = FixedWidth::Section.new('name', :align => :left)
35
+ section.options[:align].should == :left
36
+ end
37
+
38
+ it "should use a missing method to create a column" do
39
+ @section.should have(0).columns
40
+ @section.first_name 5
41
+ @section.should have(1).columns
42
+ end
43
+
44
+ it "should prevent duplicate column names without any groupings" do
45
+ @section.column :id, 10
46
+ lambda { @section.column(:id, 30) }.should raise_error(FixedWidth::DuplicateColumnNameError, /column named 'id'/)
47
+ end
48
+
49
+ it "should prevent column names that already exist as groups" do
50
+ @section.column :foo, 11, :group => :id
51
+ lambda { @section.column(:id, 30) }.should raise_error(FixedWidth::DuplicateGroupNameError, /group named 'id'/)
52
+ end
53
+
54
+ it "should prevent group names that already exist as columns" do
55
+ @section.column :foo, 11
56
+ lambda { @section.column(:id, 30, :group => :foo) }.should raise_error(FixedWidth::DuplicateGroupNameError, /column named 'foo'/)
57
+ end
58
+
59
+ it "should prevent duplicate column names within groups" do
60
+ @section.column :id, 10, :group => :foo
61
+ lambda { @section.column(:id, 30, :group => :foo) }.should raise_error(FixedWidth::DuplicateColumnNameError, /column named 'id' in the ':foo' group/)
62
+ end
63
+
64
+ it "should allow duplicate column names in different groups" do
65
+ @section.column :id, 10, :group => :foo
66
+ lambda { @section.column(:id, 30, :group => :bar) }.should_not raise_error(FixedWidth::DuplicateColumnNameError)
67
+ end
68
+
69
+ it "should allow duplicate column names that are reserved (i.e. spacer)" do
70
+ @section.spacer 10
71
+ lambda { @section.spacer 10 }.should_not raise_error(FixedWidth::DuplicateColumnNameError)
72
+ end
73
+ end
74
+
75
+ it "should accept and store the trap as a block" do
76
+ @section.trap { |v| v == 4 }
77
+ trap = @section.instance_variable_get(:@trap)
78
+ trap.should be_a(Proc)
79
+ trap.call(4).should == true
80
+ end
81
+
82
+ describe "when adding a template" do
83
+ before(:each) do
84
+ @template = mock('templated section', :columns => [1,2,3], :options => {})
85
+ @definition = mock("definition", :templates => { :test => @template } )
86
+ @section.definition = @definition
87
+ end
88
+
89
+ it "should ensure the template exists" do
90
+ @definition.stub! :templates => {}
91
+ lambda { @section.template(:none) }.should raise_error(ArgumentError)
92
+ end
93
+
94
+ it "should add the template columns to the current column list" do
95
+ @section.template :test
96
+ @section.should have(3).columns
97
+ end
98
+
99
+ it "should merge the template option" do
100
+ @section = FixedWidth::Section.new(:body, :align => :left)
101
+ @section.definition = @definition
102
+ @template.stub! :options => {:align => :right}
103
+ @section.template :test
104
+ @section.options.should == {:align => :left}
105
+ end
106
+ end
107
+
108
+ describe "when formatting a row" do
109
+ before(:each) do
110
+ @data = { :id => 3, :name => "Ryan" }
111
+ end
112
+
113
+ it "should default to string data aligned right" do
114
+ @section.column(:id, 5)
115
+ @section.column(:name, 10)
116
+ @section.format( @data ).should == " 3 Ryan"
117
+ end
118
+
119
+ it "should left align if asked" do
120
+ @section.column(:id, 5)
121
+ @section.column(:name, 10, :align => :left)
122
+ @section.format(@data).should == " 3Ryan "
123
+ end
124
+
125
+ it "should read from groups" do
126
+ @data = { :id => 3, :foo => { :name => "Ryan" } }
127
+ @section.column(:id, 5)
128
+ @section.column(:name, 10, :align => :left, :group => :foo)
129
+ @section.format(@data).should == " 3Ryan "
130
+ end
131
+ end
132
+
133
+ describe "when parsing a file" do
134
+ before(:each) do
135
+ @line = ' 45 Ryan WoódSC '
136
+ @section = FixedWidth::Section.new(:body)
137
+ @column_content = { :id => 5, :first => 10, :last => 10, :state => 2 }
138
+ end
139
+
140
+ it "should return a key for key column" do
141
+ @column_content.each { |k,v| @section.column(k, v) }
142
+ parsed = @section.parse(@line)
143
+ @column_content.each_key { |name| parsed.should have_key(name) }
144
+ end
145
+
146
+ it "should not return a key for reserved names" do
147
+ @column_content.each { |k,v| @section.column(k, v) }
148
+ @section.spacer 5
149
+ @section.should have(5).columns
150
+ parsed = @section.parse(@line)
151
+ parsed.should have(4).keys
152
+ end
153
+
154
+ it "should break columns into groups" do
155
+ @section.column(:id, 5)
156
+ @section.column(:first, 10, :group => :name)
157
+ @section.column(:last, 10, :group => :name)
158
+ @section.column(:state, 2, :group => :address)
159
+ @section.spacer 5
160
+ @section.should have(5).columns
161
+ parsed = @section.parse(@line)
162
+ parsed.should have(3).keys
163
+ parsed[:id].should == '45'
164
+ parsed[:name][:first].should == 'Ryan'
165
+ parsed[:name][:last].should == 'Woód'
166
+ parsed[:address][:state].should == 'SC'
167
+ end
168
+
169
+ it "should not die if a field is not in range" do
170
+ @section.column(:a, 5)
171
+ @section.column(:b, 5)
172
+ @section.column(:c, 5)
173
+ line = ' 45'
174
+ parsed = @section.parse(line)
175
+ parsed[:a].should == '45'
176
+ parsed[:b].should == ''
177
+ parsed[:c].should == ''
178
+ end
179
+ end
180
+
181
+ it "should try to match a line using the trap" do
182
+ @section.trap do |line|
183
+ line == 'hello'
184
+ end
185
+ @section.match('hello').should be_true
186
+ @section.match('goodbye').should be_false
187
+ end
188
+ end