dbf 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,6 @@
1
+ # 2.0.4
2
+ - memo fields return nil if memo file is missing
3
+
1
4
  # 2.0.3
2
5
  - set encoding if table encoding is nil
3
6
 
@@ -38,7 +41,7 @@
38
41
 
39
42
  # 1.6.6
40
43
  - add binary data type support to ActiveRecord schema output
41
-
44
+
42
45
  # 1.6.5
43
46
  - support for visual foxpro double (b) data type
44
47
 
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
1
  gemspec
2
- source :rubygems
2
+ source 'https://rubygems.org'
@@ -1,30 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dbf (1.7.4)
4
+ dbf (2.0.3)
5
+ fastercsv (~> 1.5.4)
5
6
 
6
7
  GEM
7
- remote: http://rubygems.org/
8
+ remote: https://rubygems.org/
8
9
  specs:
9
- diff-lcs (1.1.3)
10
- json (1.6.5)
10
+ diff-lcs (1.2.4)
11
+ fastercsv (1.5.5)
11
12
  rake (0.9.2.2)
12
- rdoc (3.12)
13
- json (~> 1.4)
14
- rspec (2.8.0)
15
- rspec-core (~> 2.8.0)
16
- rspec-expectations (~> 2.8.0)
17
- rspec-mocks (~> 2.8.0)
18
- rspec-core (2.8.0)
19
- rspec-expectations (2.8.0)
20
- diff-lcs (~> 1.1.2)
21
- rspec-mocks (2.8.0)
13
+ rspec (2.13.0)
14
+ rspec-core (~> 2.13.0)
15
+ rspec-expectations (~> 2.13.0)
16
+ rspec-mocks (~> 2.13.0)
17
+ rspec-core (2.13.1)
18
+ rspec-expectations (2.13.0)
19
+ diff-lcs (>= 1.1.3, < 2.0)
20
+ rspec-mocks (2.13.1)
22
21
 
23
22
  PLATFORMS
24
23
  ruby
25
24
 
26
25
  DEPENDENCIES
27
26
  dbf!
28
- rake (~> 0.9.2)
29
- rdoc (~> 3.11)
30
- rspec (~> 2.8.0)
27
+ rake (>= 0.9.2)
28
+ rspec (~> 2.13.0)
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
- # DBF [![Build Status](https://secure.travis-ci.org/infused/dbf.png)](http://travis-ci.org/infused/dbf)
1
+ # DBF
2
+ [![Build Status](https://secure.travis-ci.org/infused/dbf.png)](http://travis-ci.org/infused/dbf)
3
+ [![Gem Version](https://badge.fury.io/rb/dbf.png)](http://badge.fury.io/rb/dbf)
4
+ [![Code Climate](https://codeclimate.com/github/infused/dbf.png)](https://codeclimate.com/github/infused/dbf)
5
+ [![Dependency Status](https://gemnasium.com/infused/dbf.png)](https://gemnasium.com/infused/dbf)
2
6
 
3
7
  DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro
4
8
  database files
@@ -6,22 +10,22 @@ database files
6
10
  * Project page: <http://github.com/infused/dbf>
7
11
  * API Documentation: <http://rubydoc.info/github/infused/dbf/frames>
8
12
  * Report bugs: <http://github.com/infused/dbf/issues>
9
- * Questions: Email <mailto:keithm@infused.org> and put DBF somewhere in the
13
+ * Questions: Email <mailto:keithm@infused.org> and put DBF somewhere in the
10
14
  subject line
11
15
 
12
16
  ## Compatibility
13
17
 
14
18
  DBF is tested to work with the following versions of ruby:
15
19
 
16
- * MRI Ruby 1.8.6, 1.8.7, 1.9.1, 1.9.2 and 1.9.3
20
+ * MRI Ruby 1.8.6, 1.8.7, 1.9.1, 1.9.2, 1.9.3, 2.0.0
17
21
  * JRuby 1.6.x, 1.7.x
18
- * REE 1.8.6, 1.8.7
19
- * Rubinius (1.8 mode)
22
+ * REE 1.8.7
23
+ * Rubinius (1.8 and 1.9 modes)
20
24
 
21
25
  ## Installation
22
-
26
+
23
27
  gem install dbf
24
-
28
+
25
29
  ## Basic Usage
26
30
 
27
31
  Open a DBF file:
@@ -35,11 +39,11 @@ Enumerate all records
35
39
  puts record.name
36
40
  puts record.email
37
41
  end
38
-
42
+
39
43
  Find a single record
40
44
 
41
45
  widget = widgets.find(6)
42
-
46
+
43
47
  Note that find() will return nil if the requested record has been deleted
44
48
  and not yet pruned from the database.
45
49
 
@@ -49,16 +53,16 @@ ways
49
53
  widget["SlotNumber"] # original field name in dbf file
50
54
  widget['slot_number'] # underscored field name string
51
55
  widget[:slot_number] # underscored field name symbol
52
-
56
+
53
57
  Get a hash of all attributes. The keys are the original column names.
54
58
 
55
59
  widgets.attributes
56
60
  => {"Name" => "Thing1", "SlotNumber" => 1}
57
-
61
+
58
62
  Search for records using a simple hash format. Multiple search criteria are
59
63
  ANDed. Use the block form if the resulting recordset could be large, otherwise
60
64
  all records will be loaded into memory.
61
-
65
+
62
66
  # find all records with slot_number equal to s42
63
67
  widgets.find(:all, :slot_number => 's42') do |widget|
64
68
  # the record will be nil if deleted, but not yet pruned from the database
@@ -66,13 +70,13 @@ all records will be loaded into memory.
66
70
  puts widget.serial_number
67
71
  end
68
72
  end
69
-
73
+
70
74
  # find the first record with slot_number equal to s42
71
75
  widgets.find :first, :slot_number => 's42'
72
-
76
+
73
77
  # find record number 10
74
78
  widgets.find(10)
75
-
79
+
76
80
  ## Migrating to ActiveRecord
77
81
 
78
82
  An example of migrating a DBF book table to ActiveRecord using a migration:
@@ -80,12 +84,12 @@ An example of migrating a DBF book table to ActiveRecord using a migration:
80
84
  require 'dbf'
81
85
 
82
86
  class Book < ActiveRecord::Base; end
83
-
87
+
84
88
  class CreateBooks < ActiveRecord::Migration
85
89
  def self.up
86
90
  table = DBF::Table.new('db/dbf/books.dbf')
87
91
  eval(table.schema)
88
-
92
+
89
93
  Book.reset_column_information
90
94
  table.each do |record|
91
95
  Book.create(:title => record.title, :author => record.author)
@@ -96,7 +100,7 @@ An example of migrating a DBF book table to ActiveRecord using a migration:
96
100
  drop_table :books
97
101
  end
98
102
  end
99
-
103
+
100
104
  ## Command-line utility
101
105
 
102
106
  A small command-line utility called dbf is installed along with the gem.
@@ -107,16 +111,16 @@ A small command-line utility called dbf is installed along with the gem.
107
111
  -s = print summary information
108
112
  -a = create an ActiveRecord::Schema
109
113
  -c = create a csv file
110
-
114
+
111
115
  Create an executable ActiveRecord schema:
112
-
116
+
113
117
  dbf -a books.dbf > books_schema.rb
114
-
118
+
115
119
  Dump all records to a CSV file:
116
120
 
117
121
  dbf -c books.dbf > books.csv
118
-
119
- ## dBase version support
122
+
123
+ ## dBase version compatibility
120
124
 
121
125
  The basic dBase data types are generally supported well. Support for the
122
126
  advanced data types in dbase V and FoxPro are still experimental or not
@@ -135,7 +139,7 @@ for a full list of supported column types.
135
139
 
136
140
  ## License
137
141
 
138
- Copyright (c) 2006-2012 Keith Morrison <keithm@infused.org>
142
+ Copyright (c) 2006-2013 Keith Morrison <<keithm@infused.org>>
139
143
 
140
144
  Permission is hereby granted, free of charge, to any person
141
145
  obtaining a copy of this software and associated documentation
data/bin/dbf CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby -s
2
2
 
3
- require 'rubygems'
4
3
  require 'dbf'
5
4
 
6
5
  $a ||= false
@@ -23,15 +22,15 @@ else
23
22
  table = DBF::Table.new filename
24
23
  puts table.schema
25
24
  end
26
-
25
+
27
26
  if $s
28
27
  table = DBF::Table.new filename
29
28
  puts
30
29
  puts "Database: #{filename}"
31
30
  puts "Type: (#{table.version}) #{table.version_description}"
32
- puts "Memo File: #{table.has_memo_file? ? 'true' : false}"
31
+ puts "Memo File: #{table.has_memo_file? ? 'true' : 'false'}"
33
32
  puts "Records: #{table.record_count}"
34
-
33
+
35
34
  puts "\nFields:"
36
35
  puts "Name Type Length Decimal"
37
36
  puts "-" * 78
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = 'http://github.com/infused/dbf'
11
11
  s.summary = 'Read xBase files'
12
12
  s.description = 'A small fast library for reading dBase, xBase, Clipper and FoxPro database files.'
13
-
13
+
14
14
  s.executables = ['dbf']
15
15
  s.rdoc_options = ['--charset=UTF-8']
16
16
  s.extra_rdoc_files = ['README.md', 'CHANGELOG.md', 'MIT-LICENSE']
@@ -20,9 +20,9 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.required_rubygems_version = '>= 1.3.0'
22
22
  s.add_dependency 'fastercsv', '~> 1.5.4'
23
-
24
- s.add_development_dependency 'rspec', '~> 2.11.0'
25
- s.add_development_dependency 'rake', '~> 0.9.2'
23
+
24
+ s.add_development_dependency 'rspec', '~> 2.13.0'
25
+ s.add_development_dependency 'rake', '>= 0.9.2'
26
26
 
27
27
  # if RUBY_VERSION.to_f >= 1.9
28
28
  # s.add_development_dependency 'ruby-debug19'
@@ -2,7 +2,7 @@ module DBF
2
2
  module Column
3
3
  class LengthError < StandardError; end
4
4
  class NameError < StandardError; end
5
-
5
+
6
6
  class Base
7
7
  attr_reader :name, :type, :length, :decimal
8
8
 
@@ -32,7 +32,6 @@ module DBF
32
32
  when 'D' then decode_date(value)
33
33
  when 'T' then decode_datetime(value)
34
34
  when 'L' then boolean(value)
35
- when 'B' then unpack_binary(value)
36
35
  when 'M' then decode_memo(value)
37
36
  else encode_string(value.to_s).strip
38
37
  end
@@ -75,7 +74,7 @@ module DBF
75
74
  seconds = (milliseconds / 1000).to_i
76
75
  DateTime.jd(days, (seconds/3600).to_i, (seconds/60).to_i % 60, seconds % 60) rescue nil
77
76
  end
78
-
77
+
79
78
  def decode_memo(value) #nodoc
80
79
  encode_string(value) if value
81
80
  end
@@ -88,9 +87,6 @@ module DBF
88
87
  value.unpack('V')[0]
89
88
  end
90
89
 
91
- def unpack_binary(value) #nodoc
92
- end
93
-
94
90
  def boolean(value) #nodoc
95
91
  value.strip =~ /^(y|t)$/i ? true : false
96
92
  end
@@ -2,33 +2,34 @@ module DBF
2
2
  module Memo
3
3
  class Base
4
4
  BLOCK_HEADER_SIZE = 8
5
-
5
+ BLOCK_SIZE = 512
6
+
6
7
  def self.open(filename, version)
7
8
  self.new File.open(filename, 'rb'), version
8
9
  end
9
-
10
+
10
11
  def initialize(data, version)
11
12
  @data, @version = data, version
12
13
  end
13
-
14
+
14
15
  def get(start_block)
15
16
  if start_block > 0
16
- build_memo start_block
17
+ build_memo start_block
17
18
  end
18
19
  end
19
-
20
+
20
21
  def close
21
22
  @data.close && @data.closed?
22
23
  end
23
-
24
+
24
25
  def closed?
25
26
  @data.closed?
26
27
  end
27
-
28
+
28
29
  private
29
-
30
+
30
31
  def offset(start_block) #nodoc
31
- start_block * block_size
32
+ start_block * BLOCK_SIZE
32
33
  end
33
34
 
34
35
  def content_size(memo_size) #nodoc
@@ -38,10 +39,6 @@ module DBF
38
39
  def block_content_size #nodoc
39
40
  @block_content_size ||= block_size - BLOCK_HEADER_SIZE
40
41
  end
41
-
42
- def block_size #nodoc
43
- 512
44
- end
45
42
  end
46
43
  end
47
44
  end
@@ -5,9 +5,9 @@ module DBF
5
5
  @data.seek offset(start_block)
6
6
  memo_string = ""
7
7
  begin
8
- block = @data.read(block_size).gsub(/(\000|\032)/, '')
8
+ block = @data.read(BLOCK_SIZE).gsub(/(\000|\032)/, '')
9
9
  memo_string << block
10
- end until block.size < block_size
10
+ end until block.size < BLOCK_SIZE
11
11
  memo_string
12
12
  end
13
13
  end
@@ -1,8 +1,8 @@
1
1
  module DBF
2
- # An instance of DBF::Record represents a row in the DBF file
2
+ # An instance of DBF::Record represents a row in the DBF file
3
3
  class Record
4
4
  # Initialize a new DBF::Record
5
- #
5
+ #
6
6
  # @data [String, StringIO] data
7
7
  # @columns [Column]
8
8
  # @version [String]
@@ -11,7 +11,7 @@ module DBF
11
11
  @data = StringIO.new(data)
12
12
  @columns, @version, @memo = columns, version, memo
13
13
  end
14
-
14
+
15
15
  # Equality
16
16
  #
17
17
  # @param [DBF::Record] other
@@ -19,14 +19,14 @@ module DBF
19
19
  def ==(other)
20
20
  other.respond_to?(:attributes) && other.attributes == attributes
21
21
  end
22
-
22
+
23
23
  # Maps a row to an array of values
24
- #
24
+ #
25
25
  # @return [Array]
26
26
  def to_a
27
27
  @columns.map {|column| attributes[column.name]}
28
28
  end
29
-
29
+
30
30
  # Do all search parameters match?
31
31
  #
32
32
  # @param [Hash] options
@@ -44,12 +44,12 @@ module DBF
44
44
  attributes[@columns[index].name]
45
45
  end
46
46
  end
47
-
47
+
48
48
  # @return [Hash]
49
49
  def attributes
50
50
  @attributes ||= Hash[@columns.map {|column| [column.name, init_attribute(column)]}]
51
51
  end
52
-
52
+
53
53
  def respond_to?(method, *args)
54
54
  return true if column_names.include?(method.to_s)
55
55
  super
@@ -68,27 +68,25 @@ module DBF
68
68
  def column_names
69
69
  @column_names ||= @columns.map {|column| column.underscored_name}
70
70
  end
71
-
71
+
72
72
  def init_attribute(column) #nodoc
73
73
  value = if column.memo?
74
- @memo.get get_memo_start_block(column)
74
+ @memo && @memo.get(memo_start_block(column))
75
75
  else
76
76
  unpack_data(column)
77
77
  end
78
- column.type_cast value
78
+ column.type_cast(value)
79
79
  end
80
-
81
- def get_memo_start_block(column) #nodoc
82
- if %w(30 31).include?(@version)
83
- @data.read(column.length).unpack('V').first
84
- else
85
- unpack_data(column).to_i
86
- end
80
+
81
+ def memo_start_block(column) #nodoc
82
+ format = 'V' if %w(30 31).include?(@version)
83
+ unpack_data(column, format).to_i
87
84
  end
88
85
 
89
- def unpack_data(column) #nodoc
90
- @data.read(column.length).unpack("a#{column.length}").first
86
+ def unpack_data(column, format=nil) #nodoc
87
+ format ||= "a#{column.length}"
88
+ @data.read(column.length).unpack(format).first
91
89
  end
92
-
90
+
93
91
  end
94
92
  end