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.
- data/COPYING +10 -0
- data/HISTORY +17 -0
- data/README.markdown +149 -0
- data/Rakefile +49 -0
- data/TODO +7 -0
- data/VERSION +1 -0
- data/examples/readme_example.rb +62 -0
- data/fixed_width-multibyte.gemspec +69 -0
- data/fixed_width.gemspec +76 -0
- data/lib/fixed_width.rb +14 -0
- data/lib/fixed_width/column.rb +86 -0
- data/lib/fixed_width/core_ext/symbol.rb +17 -0
- data/lib/fixed_width/definition.rb +31 -0
- data/lib/fixed_width/fixed_width.rb +84 -0
- data/lib/fixed_width/generator.rb +20 -0
- data/lib/fixed_width/parser.rb +47 -0
- data/lib/fixed_width/section.rb +90 -0
- data/spec/column_spec.rb +205 -0
- data/spec/definition_spec.rb +81 -0
- data/spec/fixed_width_spec.rb +81 -0
- data/spec/generator_spec.rb +48 -0
- data/spec/parser_spec.rb +110 -0
- data/spec/section_spec.rb +188 -0
- data/spec/spec_helper.rb +4 -0
- metadata +98 -0
| @@ -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
         | 
    
        data/spec/parser_spec.rb
    ADDED
    
    | @@ -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
         |