fixed_width-multibyte 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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