dbf 3.1.3 → 4.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05f4c5675dae61be9046beaf3dab5cf09d16752bdfa5b3841f7811fe4e08b981
4
- data.tar.gz: 7dd76a7c629a0965557d2c4fae8043ac7e5811834e3e011ea55ab669678a238c
3
+ metadata.gz: 4c2ff24f150ee6567de0532c773695f8b47c0db811660e0f5f3be3d53a7cc053
4
+ data.tar.gz: 7006275aff71326833452546657bb07520d53024b6846b0c982121a488cd8235
5
5
  SHA512:
6
- metadata.gz: eeb040f9f564e605a0fb107c43558d060c55ff868cadccfdfdd5b452040cc0ec30261ed0db0eb31ff8891efb6f1e57305743b6176f90ed3a7508186166e80752
7
- data.tar.gz: 303215437b2339e83436e8999c9b2465ac69ee48a2be591c63e77a1c53968accfcb1c84a5160174d47665dd6af561721dcb255777db9861a442452a399342015
6
+ metadata.gz: b2d4bffa8201a8fa07abf642e721523e7ed59bb2b3e9a0fae31fe5ce6a4a3078f1520eb09e350d979dd88a68801c7c52d3236c402f83a41da1e5e6c4bca39911
7
+ data.tar.gz: fddf6622338b52b4bb6006513a92d9fd44c8f1e864738fd597d7e9f3fc21bcd86707f5e68e76216bd4c6d3be7dad9a48e5e19d55a6728691f6d90d86ec6db25e
@@ -1,3 +1,18 @@
1
+ # 4.1.3
2
+ - Raise DBF::NoColumnsDefined error when attempting to read records if no columns are defined
3
+
4
+ # 4.1.1
5
+ - Add required_ruby_version to gemspec
6
+
7
+ # 4.1.0
8
+ - Return Time instead of DateTime
9
+
10
+ # 4.0.0
11
+ - Drop support for ruby-2.2 and earlier
12
+
13
+ # 3.1.3
14
+ - Ensure malformed dates return nil
15
+
1
16
  # 3.1.2
2
17
  - Fix incorrect columns list when StringIO and encoding set
3
18
 
data/Gemfile CHANGED
@@ -4,9 +4,13 @@ source 'https://rubygems.org'
4
4
  group :development, :test do
5
5
  gem 'awesome_print'
6
6
  gem 'byebug'
7
+ gem 'e2mmap'
7
8
  gem 'guard'
8
9
  gem 'guard-rspec'
10
+ gem 'irb'
9
11
  gem 'rake'
10
- gem 'rubocop'
11
12
  gem 'rspec'
13
+ gem 'rubocop'
14
+ gem 'rubocop-performance'
15
+ gem 'rubocop-rspec'
12
16
  end
@@ -1,19 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dbf (3.1.3)
4
+ dbf (4.1.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.0)
10
10
  awesome_print (1.8.0)
11
- byebug (10.0.2)
11
+ byebug (11.0.1)
12
12
  coderay (1.1.2)
13
13
  diff-lcs (1.3)
14
- ffi (1.9.25)
14
+ e2mmap (0.1.0)
15
+ ffi (1.11.1)
15
16
  formatador (0.2.5)
16
- guard (2.14.2)
17
+ guard (2.15.0)
17
18
  formatador (>= 0.2.4)
18
19
  listen (>= 2.7, < 4.0)
19
20
  lumberjack (>= 1.0.12, < 2.0)
@@ -27,55 +28,58 @@ GEM
27
28
  guard (~> 2.1)
28
29
  guard-compat (~> 1.1)
29
30
  rspec (>= 2.99.0, < 4.0)
30
- jaro_winkler (1.5.1)
31
+ irb (1.0.0)
32
+ jaro_winkler (1.5.3)
31
33
  listen (3.1.5)
32
34
  rb-fsevent (~> 0.9, >= 0.9.4)
33
35
  rb-inotify (~> 0.9, >= 0.9.7)
34
36
  ruby_dep (~> 1.2)
35
37
  lumberjack (1.0.13)
36
- method_source (0.9.0)
38
+ method_source (0.9.2)
37
39
  nenv (0.3.0)
38
40
  notiffany (0.1.1)
39
41
  nenv (~> 0.1)
40
42
  shellany (~> 0.0)
41
- parallel (1.12.1)
42
- parser (2.5.1.2)
43
+ parallel (1.17.0)
44
+ parser (2.6.3.0)
43
45
  ast (~> 2.4.0)
44
- powerpack (0.1.2)
45
- pry (0.11.3)
46
+ pry (0.12.2)
46
47
  coderay (~> 1.1.0)
47
48
  method_source (~> 0.9.0)
48
49
  rainbow (3.0.0)
49
- rake (12.3.1)
50
+ rake (12.3.2)
50
51
  rb-fsevent (0.10.3)
51
- rb-inotify (0.9.10)
52
- ffi (>= 0.5.0, < 2)
52
+ rb-inotify (0.10.0)
53
+ ffi (~> 1.0)
53
54
  rspec (3.8.0)
54
55
  rspec-core (~> 3.8.0)
55
56
  rspec-expectations (~> 3.8.0)
56
57
  rspec-mocks (~> 3.8.0)
57
- rspec-core (3.8.0)
58
+ rspec-core (3.8.2)
58
59
  rspec-support (~> 3.8.0)
59
- rspec-expectations (3.8.1)
60
+ rspec-expectations (3.8.4)
60
61
  diff-lcs (>= 1.2.0, < 2.0)
61
62
  rspec-support (~> 3.8.0)
62
- rspec-mocks (3.8.0)
63
+ rspec-mocks (3.8.1)
63
64
  diff-lcs (>= 1.2.0, < 2.0)
64
65
  rspec-support (~> 3.8.0)
65
- rspec-support (3.8.0)
66
- rubocop (0.59.2)
66
+ rspec-support (3.8.2)
67
+ rubocop (0.73.0)
67
68
  jaro_winkler (~> 1.5.1)
68
69
  parallel (~> 1.10)
69
- parser (>= 2.5, != 2.5.1.1)
70
- powerpack (~> 0.1)
70
+ parser (>= 2.6)
71
71
  rainbow (>= 2.2.2, < 4.0)
72
72
  ruby-progressbar (~> 1.7)
73
- unicode-display_width (~> 1.0, >= 1.0.1)
74
- ruby-progressbar (1.10.0)
73
+ unicode-display_width (>= 1.4.0, < 1.7)
74
+ rubocop-performance (1.4.0)
75
+ rubocop (>= 0.71.0)
76
+ rubocop-rspec (1.33.0)
77
+ rubocop (>= 0.60.0)
78
+ ruby-progressbar (1.10.1)
75
79
  ruby_dep (1.5.0)
76
80
  shellany (0.0.1)
77
- thor (0.20.0)
78
- unicode-display_width (1.4.0)
81
+ thor (0.20.3)
82
+ unicode-display_width (1.6.0)
79
83
 
80
84
  PLATFORMS
81
85
  ruby
@@ -84,11 +88,15 @@ DEPENDENCIES
84
88
  awesome_print
85
89
  byebug
86
90
  dbf!
91
+ e2mmap
87
92
  guard
88
93
  guard-rspec
94
+ irb
89
95
  rake
90
96
  rspec
91
97
  rubocop
98
+ rubocop-performance
99
+ rubocop-rspec
92
100
 
93
101
  BUNDLED WITH
94
- 1.16.5
102
+ 2.1.4
data/Guardfile CHANGED
@@ -6,6 +6,6 @@ guard :rspec, cmd: 'bundle exec rspec' do
6
6
  # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
7
  watch(%r{^lib/(.+)\.rb$}) { 'spec' }
8
8
  watch('spec/spec_helper.rb') { 'spec' }
9
- watch(/spec\/fixtures\/(.+)/) { 'spec' }
9
+ watch(%r{spec/fixtures/(.+)}) { 'spec' }
10
10
  watch('Guardfile') { 'spec' }
11
11
  end
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2006-2018 Keith Morrison <keithm@infused.org>
1
+ Copyright (c) 2006-2020 Keith Morrison <keithm@infused.org>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -16,14 +16,17 @@ database files
16
16
  subject line
17
17
  * Change log: <https://github.com/infused/dbf/blob/master/CHANGELOG.md>
18
18
 
19
- NOTE: beginning with version 3 we have dropped support for Ruby 1.8 and 1.9. If you need support for older Rubies, please use 2.0.x (https://github.com/infused/dbf/tree/2_stable)
19
+ NOTE: Beginning with version 4 we have dropped support for Ruby 2.0, 2.1, 2.2, and 2.3. If you need support for these older Rubies,
20
+ please use 3.0.x (https://github.com/infused.org/dbf/tree/3_stable)
21
+
22
+ NOTE: Beginning with version 3 we have dropped support for Ruby 1.8 and 1.9. If you need support for older Rubies,
23
+ please use 2.0.x (https://github.com/infused/dbf/tree/2_stable)
20
24
 
21
25
  ## Compatibility
22
26
 
23
27
  DBF is tested to work with the following versions of Ruby:
24
28
 
25
- * MRI Ruby 2.0.x, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.x
26
- * JRuby 1.7.x
29
+ * Ruby 2.4.x, 2.5.x, 2.6.x, 2.7.x
27
30
 
28
31
  ## Installation
29
32
 
@@ -208,7 +211,7 @@ Sequel.migration do
208
211
  end
209
212
  ```
210
213
 
211
- If you have initalized the DBF::Table with raw data, you will need to set the
214
+ If you have initialized the DBF::Table with raw data, you will need to set the
212
215
  exported table name manually:
213
216
 
214
217
  ```ruby
@@ -226,7 +229,7 @@ A small command-line utility called dbf is installed along with the gem.
226
229
  -s = print summary information
227
230
  -a = create an ActiveRecord::Schema
228
231
  -r = create a Sequel Migration
229
- -c = dump data in CSV format
232
+ -c = export as CSV
230
233
 
231
234
  Create an executable ActiveRecord schema:
232
235
 
@@ -272,7 +275,7 @@ for a full list of supported column types.
272
275
 
273
276
  ## License
274
277
 
275
- Copyright (c) 2006-2018 Keith Morrison <<keithm@infused.org>>
278
+ Copyright (c) 2006-2020 Keith Morrison <<keithm@infused.org>>
276
279
 
277
280
  Permission is hereby granted, free of charge, to any person
278
281
  obtaining a copy of this software and associated documentation
data/bin/dbf CHANGED
@@ -9,14 +9,14 @@ params = ARGV.getopts('h', 's', 'a', 'c', 'r', 'v')
9
9
  if params['v']
10
10
  puts "dbf version: #{DBF::VERSION}"
11
11
 
12
- elsif params['h'] then
12
+ elsif params['h']
13
13
  puts "usage: #{File.basename(__FILE__)} [-h|-s|-a|-c|-r] filename"
14
14
  puts ' -h = print this message'
15
15
  puts ' -v = print the DBF gem version'
16
16
  puts ' -s = print summary information'
17
17
  puts ' -a = create an ActiveRecord::Schema'
18
18
  puts ' -r = create a Sequel migration'
19
- puts ' -c = create a CSV file'
19
+ puts ' -c = export as CSV'
20
20
  else
21
21
 
22
22
  filename = ARGV.shift
@@ -46,7 +46,7 @@ else
46
46
  puts 'Name Type Length Decimal'
47
47
  puts '-' * 78
48
48
  table.columns.each do |f|
49
- puts '%-16s %-10s %-10s %-10s' % [f.name, f.type, f.length, f.decimal]
49
+ puts format('%-16s %-10s %-10s %-10s', f.name, f.type, f.length, f.decimal)
50
50
  end
51
51
  end
52
52
 
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib/', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
3
3
  require 'dbf/version'
4
4
 
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
19
19
  s.test_files = Dir.glob('spec/**/*_spec.rb')
20
20
  s.require_paths = ['lib']
21
21
  s.required_rubygems_version = Gem::Requirement.new('>= 1.3.0')
22
+ s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
22
23
  end
@@ -1,36 +1,21 @@
1
1
  # DBF supported data types
2
2
 
3
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4
- | Version | Description | C | N | L | D | M | F | B | G | P | Y | T | I | V | X | @ | O | + |
5
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
6
- | 02 | FoxBase | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
7
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8
- | 03 | dBase III without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
9
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
10
- | 04 | dBase IV without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
11
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
12
- | 05 | dBase V without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
13
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
14
- | 07 | Visual Objects 1.x | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
15
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
16
- | 30 | Visual FoxPro | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | - |
17
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
18
- | 31 | Visual FoxPro with AutoIncrement | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
19
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
20
- | 7b | dBase IV with memo file | Y | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - |
21
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
22
- | 83 | dBase III with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - |
23
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
24
- | 87 | Visual Objects 1.x with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - |
25
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
26
- | 8b | dBase IV with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | N | - | - | - |
27
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
28
- | 8e | dBase IV with SQL table | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | N | - | - | - |
29
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
30
- | f5 | FoxPro with memo file | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
31
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
32
- | fb | FoxPro without memo file | Y | Y | Y | Y | - | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
33
- +---------+-----------------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3
+ | Version | Description | C | N | L | D | M | F | B | G | P | Y | T | I | V | X | @ | O | + |
4
+ |---------|-----------------------------------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5
+ | 02 | FoxBase | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
6
+ | 03 | dBase III without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
7
+ | 04 | dBase IV without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
8
+ | 05 | dBase V without memo file | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
9
+ | 07 | Visual Objects 1.x | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - | - |
10
+ | 30 | Visual FoxPro | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | - |
11
+ | 31 | Visual FoxPro with AutoIncrement | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
12
+ | 7b | dBase IV with memo file | Y | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - |
13
+ | 83 | dBase III with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - |
14
+ | 87 | Visual Objects 1.x with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | - | - | - | - |
15
+ | 8b | dBase IV with memo file | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | N | - | - | - |
16
+ | 8e | dBase IV with SQL table | Y | Y | Y | Y | Y | - | - | - | - | - | - | - | - | N | - | - | - |
17
+ | f5 | FoxPro with memo file | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
18
+ | fb | FoxPro without memo file | Y | Y | Y | Y | - | Y | Y | Y | N | Y | N | Y | N | N | N | N | N |
34
19
 
35
20
  Data type descriptions
36
21
 
data/lib/dbf.rb CHANGED
@@ -1,7 +1,8 @@
1
- require 'date'
2
-
3
1
  require 'csv'
2
+ require 'date'
3
+ require 'forwardable'
4
4
  require 'json'
5
+ require 'time'
5
6
 
6
7
  require 'dbf/version'
7
8
  require 'dbf/schema'
@@ -1,5 +1,7 @@
1
1
  module DBF
2
2
  class Column
3
+ extend Forwardable
4
+
3
5
  class LengthError < StandardError
4
6
  end
5
7
 
@@ -7,6 +9,7 @@ module DBF
7
9
  end
8
10
 
9
11
  attr_reader :table, :name, :type, :length, :decimal
12
+ def_delegator :type_cast_class, :type_cast
10
13
 
11
14
  TYPE_CAST_CLASS = {
12
15
  N: ColumnType::Number,
@@ -56,14 +59,6 @@ module DBF
56
59
  {name: name, type: type, length: length, decimal: decimal}
57
60
  end
58
61
 
59
- # Cast value to native type
60
- #
61
- # @param [String] value
62
- # @return [Integer, Float, Date, DateTime, Boolean, String]
63
- def type_cast(value)
64
- type_cast_class.type_cast(value)
65
- end
66
-
67
62
  # Underscored name
68
63
  #
69
64
  # This is the column name converted to underscore format.
@@ -1,11 +1,6 @@
1
1
  module DBF
2
2
  module ColumnType
3
3
  class Base
4
- ENCODING_ARGS = [
5
- Encoding.default_external,
6
- {undef: :replace, invalid: :replace}
7
- ].freeze
8
-
9
4
  attr_reader :decimal, :encoding
10
5
 
11
6
  def initialize(decimal, encoding)
@@ -15,7 +10,7 @@ module DBF
15
10
  end
16
11
 
17
12
  class Nil < Base
18
- def type_cast(value)
13
+ def type_cast(_value)
19
14
  nil
20
15
  end
21
16
  end
@@ -23,19 +18,20 @@ module DBF
23
18
  class Number < Base
24
19
  def type_cast(value)
25
20
  return nil if value.strip.empty?
21
+
26
22
  @decimal.zero? ? value.to_i : value.to_f
27
23
  end
28
24
  end
29
25
 
30
26
  class Currency < Base
31
27
  def type_cast(value)
32
- (value.unpack('q<')[0] / 10_000.0).to_f
28
+ (value.unpack1('q<') / 10_000.0).to_f
33
29
  end
34
30
  end
35
31
 
36
32
  class SignedLong < Base
37
33
  def type_cast(value)
38
- value.unpack('l<')[0]
34
+ value.unpack1('l<')
39
35
  end
40
36
  end
41
37
 
@@ -47,20 +43,20 @@ module DBF
47
43
 
48
44
  class Double < Base
49
45
  def type_cast(value)
50
- value.unpack('E')[0]
46
+ value.unpack1('E')
51
47
  end
52
48
  end
53
49
 
54
50
  class Boolean < Base
55
51
  def type_cast(value)
56
- value.strip =~ /^(y|t)$/i ? true : false
52
+ value.strip.match?(/^(y|t)$/i)
57
53
  end
58
54
  end
59
55
 
60
56
  class Date < Base
61
57
  def type_cast(value)
62
- value =~ /\d{8}/ && ::Date.strptime(value, '%Y%m%d')
63
- rescue
58
+ value.match?(/\d{8}/) && ::Date.strptime(value, '%Y%m%d')
59
+ rescue StandardError
64
60
  nil
65
61
  end
66
62
  end
@@ -69,8 +65,8 @@ module DBF
69
65
  def type_cast(value)
70
66
  days, msecs = value.unpack('l2')
71
67
  secs = (msecs / 1000).to_i
72
- ::DateTime.jd(days, (secs / 3600).to_i, (secs / 60).to_i % 60, secs % 60)
73
- rescue
68
+ ::DateTime.jd(days, (secs / 3600).to_i, (secs / 60).to_i % 60, secs % 60).to_time
69
+ rescue StandardError
74
70
  nil
75
71
  end
76
72
  end
@@ -78,7 +74,7 @@ module DBF
78
74
  class Memo < Base
79
75
  def type_cast(value)
80
76
  if encoding && !value.nil?
81
- value.force_encoding(@encoding).encode(*ENCODING_ARGS)
77
+ value.force_encoding(@encoding).encode(Encoding.default_external, undef: :replace, invalid: :replace)
82
78
  else
83
79
  value
84
80
  end
@@ -94,9 +90,8 @@ module DBF
94
90
  class String < Base
95
91
  def type_cast(value)
96
92
  value = value.strip
97
- @encoding ? value.force_encoding(@encoding).encode(*ENCODING_ARGS) : value
93
+ @encoding ? value.force_encoding(@encoding).encode(Encoding.default_external, undef: :replace, invalid: :replace) : value
98
94
  end
99
95
  end
100
-
101
96
  end
102
97
  end
@@ -45,9 +45,7 @@ module DBF
45
45
  glob = File.join(@dirname, "#{name}.dbf")
46
46
  path = Dir.glob(glob, File::FNM_CASEFOLD).first
47
47
 
48
- unless path && File.exist?(path)
49
- raise DBF::FileNotFoundError, "related table not found: #{name}"
50
- end
48
+ raise DBF::FileNotFoundError, "related table not found: #{name}" unless path && File.exist?(path)
51
49
 
52
50
  path
53
51
  end
@@ -15,6 +15,7 @@ module DBF
15
15
 
16
16
  def get(start_block)
17
17
  return nil unless start_block > 0
18
+
18
19
  build_memo start_block
19
20
  end
20
21
 
@@ -3,7 +3,7 @@ module DBF
3
3
  class Dbase4 < Base
4
4
  def build_memo(start_block) # :nodoc:
5
5
  @data.seek offset(start_block)
6
- @data.read(@data.read(BLOCK_HEADER_SIZE).unpack('x4L').first)
6
+ @data.read(@data.read(BLOCK_HEADER_SIZE).unpack1('x4L'))
7
7
  end
8
8
  end
9
9
  end
@@ -15,8 +15,7 @@ module DBF
15
15
  memo_string = memo_string[0, memo_size]
16
16
  end
17
17
  memo_string
18
-
19
- rescue
18
+ rescue StandardError
20
19
  nil
21
20
  end
22
21
 
@@ -25,7 +24,7 @@ module DBF
25
24
  def block_size # :nodoc:
26
25
  @block_size ||= begin
27
26
  @data.rewind
28
- @data.read(FPT_HEADER_SIZE).unpack('x6n').first || 0
27
+ @data.read(FPT_HEADER_SIZE).unpack1('x6n') || 0
29
28
  end
30
29
  end
31
30
  end
@@ -83,7 +83,7 @@ module DBF
83
83
 
84
84
  def memo_start_block(column) # :nodoc:
85
85
  data = get_data(column)
86
- data = data.unpack('V').first if %w[30 31].include?(@version)
86
+ data = data.unpack1('V') if %w[30 31].include?(@version)
87
87
  data.to_i
88
88
  end
89
89
 
@@ -2,9 +2,13 @@ module DBF
2
2
  class FileNotFoundError < StandardError
3
3
  end
4
4
 
5
+ class NoColumnsDefined < StandardError
6
+ end
7
+
5
8
  # DBF::Table is the primary interface to a single DBF file and provides
6
9
  # methods for enumerating and searching the records.
7
10
  class Table
11
+ extend Forwardable
8
12
  include Enumerable
9
13
  include ::DBF::Schema
10
14
 
@@ -40,6 +44,11 @@ module DBF
40
44
  attr_accessor :encoding
41
45
  attr_writer :name
42
46
 
47
+ def_delegator :header, :header_length
48
+ def_delegator :header, :record_count
49
+ def_delegator :header, :record_length
50
+ def_delegator :header, :version
51
+
43
52
  # Opens a DBF::Table
44
53
  # Examples:
45
54
  # # working with a file stored on the filesystem
@@ -104,12 +113,14 @@ module DBF
104
113
  #
105
114
  # @yield [nil, DBF::Record]
106
115
  def each
107
- header.record_count.times { |i| yield record(i) }
116
+ record_count.times { |i| yield record(i) }
108
117
  end
109
118
 
110
119
  # @return [String]
111
120
  def filename
112
- File.basename(@data.path) if @data.respond_to?(:path)
121
+ return unless @data.respond_to?(:path)
122
+
123
+ File.basename(@data.path)
113
124
  end
114
125
 
115
126
  # Find records using a simple ActiveRecord-like syntax.
@@ -167,20 +178,17 @@ module DBF
167
178
  # @param [Integer] index
168
179
  # @return [DBF::Record, NilClass]
169
180
  def record(index)
181
+ raise DBF::NoColumnsDefined, 'The DBF file has no columns defined' if columns.empty?
182
+
170
183
  seek_to_record(index)
171
184
  return nil if deleted_record?
172
- DBF::Record.new(@data.read(header.record_length), columns, version, @memo)
185
+
186
+ record_data = @data.read(record_length)
187
+ DBF::Record.new(record_data, columns, version, @memo)
173
188
  end
174
189
 
175
190
  alias row record
176
191
 
177
- # Total number of records
178
- #
179
- # @return [Integer]
180
- def record_count
181
- @record_count ||= header.record_count
182
- end
183
-
184
192
  # Dumps all records to a CSV file. If no filename is given then CSV is
185
193
  # output to STDOUT.
186
194
  #
@@ -192,13 +200,6 @@ module DBF
192
200
  each { |record| csv << record.to_a }
193
201
  end
194
202
 
195
- # Internal dBase version number
196
- #
197
- # @return [String]
198
- def version
199
- @version ||= header.version
200
- end
201
-
202
203
  # Human readable version description
203
204
  #
204
205
  # @return [String]
@@ -222,7 +223,7 @@ module DBF
222
223
 
223
224
  def deleted_record? # :nodoc:
224
225
  flag = @data.read(1)
225
- flag ? flag.unpack('a') == ['*'] : true
226
+ flag ? flag.unpack1('a') == '*' : true
226
227
  end
227
228
 
228
229
  def end_of_record? # :nodoc:
@@ -232,6 +233,7 @@ module DBF
232
233
  def find_all(options) # :nodoc:
233
234
  select do |record|
234
235
  next unless record && record.match?(options)
236
+
235
237
  yield record if block_given?
236
238
  record
237
239
  end
@@ -242,7 +244,7 @@ module DBF
242
244
  end
243
245
 
244
246
  def foxpro? # :nodoc:
245
- FOXPRO_VERSIONS.keys.include? version
247
+ FOXPRO_VERSIONS.key?(version)
246
248
  end
247
249
 
248
250
  def header # :nodoc:
@@ -290,11 +292,11 @@ module DBF
290
292
  end
291
293
 
292
294
  def seek(offset) # :nodoc:
293
- @data.seek(header.header_length + offset)
295
+ @data.seek(header_length + offset)
294
296
  end
295
297
 
296
298
  def seek_to_record(index) # :nodoc:
297
- seek(index * header.record_length)
299
+ seek(index * record_length)
298
300
  end
299
301
  end
300
302
  end
@@ -1,3 +1,3 @@
1
1
  module DBF
2
- VERSION = '3.1.3'
2
+ VERSION = '4.1.3'.freeze
3
3
  end
@@ -42,7 +42,7 @@ RSpec.describe DBF::Column do
42
42
  end
43
43
  end
44
44
 
45
- context '#type_cast' do
45
+ describe '#type_cast' do
46
46
  context 'with type N (number)' do
47
47
  context 'when value is empty' do
48
48
  it 'returns nil' do
@@ -52,14 +52,14 @@ RSpec.describe DBF::Column do
52
52
  end
53
53
  end
54
54
 
55
- context 'and 0 length' do
55
+ context 'with 0 length' do
56
56
  it 'returns nil' do
57
57
  column = DBF::Column.new table, 'ColumnName', 'N', 0, 0
58
58
  expect(column.type_cast('')).to be_nil
59
59
  end
60
60
  end
61
61
 
62
- context 'and 0 decimals' do
62
+ context 'with 0 decimals' do
63
63
  it 'casts value to Integer' do
64
64
  value = '135'
65
65
  column = DBF::Column.new table, 'ColumnName', 'N', 3, 0
@@ -69,11 +69,11 @@ RSpec.describe DBF::Column do
69
69
  it 'supports negative Integer' do
70
70
  value = '-135'
71
71
  column = DBF::Column.new table, 'ColumnName', 'N', 3, 0
72
- expect(column.type_cast(value)).to eq (-135)
72
+ expect(column.type_cast(value)).to eq(-135)
73
73
  end
74
74
  end
75
75
 
76
- context 'and more than 0 decimals' do
76
+ context 'with more than 0 decimals' do
77
77
  it 'casts value to Float' do
78
78
  value = '13.5'
79
79
  column = DBF::Column.new table, 'ColumnName', 'N', 2, 1
@@ -83,13 +83,13 @@ RSpec.describe DBF::Column do
83
83
  it 'casts negative value to Float' do
84
84
  value = '-13.5'
85
85
  column = DBF::Column.new table, 'ColumnName', 'N', 2, 1
86
- expect(column.type_cast(value)).to eq (-13.5)
86
+ expect(column.type_cast(value)).to eq(-13.5)
87
87
  end
88
88
  end
89
89
  end
90
90
 
91
91
  context 'with type F (float)' do
92
- context 'and 0 length' do
92
+ context 'with 0 length' do
93
93
  it 'returns nil' do
94
94
  column = DBF::Column.new table, 'ColumnName', 'F', 0, 0
95
95
  expect(column.type_cast('')).to be_nil
@@ -105,7 +105,7 @@ RSpec.describe DBF::Column do
105
105
  it 'casts negative value to Float' do
106
106
  value = '-135'
107
107
  column = DBF::Column.new table, 'ColumnName', 'F', 3, 0
108
- expect(column.type_cast(value)).to eq (-135.0)
108
+ expect(column.type_cast(value)).to eq(-135.0)
109
109
  end
110
110
  end
111
111
 
@@ -126,13 +126,13 @@ RSpec.describe DBF::Column do
126
126
  it 'supports negative binary' do
127
127
  column = DBF::Column.new table, 'ColumnName', 'B', 1, 2
128
128
  expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to be_a(Float)
129
- expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to eq (-174.0)
129
+ expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to eq(-174.0)
130
130
  end
131
131
  end
132
132
  end
133
133
 
134
134
  context 'with type I (integer)' do
135
- context 'and 0 length' do
135
+ context 'with 0 length' do
136
136
  it 'returns nil' do
137
137
  column = DBF::Column.new table, 'ColumnName', 'I', 0, 0
138
138
  expect(column.type_cast('')).to be_nil
@@ -142,13 +142,13 @@ RSpec.describe DBF::Column do
142
142
  it 'casts value to Integer' do
143
143
  value = "\203\171\001\000"
144
144
  column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
145
- expect(column.type_cast(value)).to eq 96643
145
+ expect(column.type_cast(value)).to eq 96_643
146
146
  end
147
147
 
148
148
  it 'supports negative Integer' do
149
149
  value = "\x24\xE1\xFF\xFF"
150
150
  column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
151
- expect(column.type_cast(value)).to eq (-7900)
151
+ expect(column.type_cast(value)).to eq(-7900)
152
152
  end
153
153
  end
154
154
 
@@ -167,7 +167,7 @@ RSpec.describe DBF::Column do
167
167
  expect(column.type_cast('n')).to be false
168
168
  end
169
169
 
170
- context 'and 0 length' do
170
+ context 'with 0 length' do
171
171
  it 'returns nil' do
172
172
  column = DBF::Column.new table, 'ColumnName', 'L', 0, 0
173
173
  expect(column.type_cast('')).to be_nil
@@ -180,7 +180,7 @@ RSpec.describe DBF::Column do
180
180
 
181
181
  context 'with valid datetime' do
182
182
  it 'casts to DateTime' do
183
- expect(column.type_cast("Nl%\000\300Z\252\003")).to eq DateTime.parse('2002-10-10T17:04:56+00:00')
183
+ expect(column.type_cast("Nl%\000\300Z\252\003")).to eq Time.parse('2002-10-10T17:04:56+00:00')
184
184
  end
185
185
  end
186
186
 
@@ -190,7 +190,7 @@ RSpec.describe DBF::Column do
190
190
  end
191
191
  end
192
192
 
193
- context 'and 0 length' do
193
+ context 'with 0 length' do
194
194
  it 'returns nil' do
195
195
  column = DBF::Column.new table, 'ColumnName', 'T', 0, 0
196
196
  expect(column.type_cast('')).to be_nil
@@ -203,7 +203,7 @@ RSpec.describe DBF::Column do
203
203
 
204
204
  context 'with valid date' do
205
205
  it 'casts to Date' do
206
- expect(column.type_cast('20050712')).to eq Date.new(2005,7,12)
206
+ expect(column.type_cast('20050712')).to eq Date.new(2005, 7, 12)
207
207
  end
208
208
  end
209
209
 
@@ -213,7 +213,7 @@ RSpec.describe DBF::Column do
213
213
  end
214
214
  end
215
215
 
216
- context 'and 0 length' do
216
+ context 'with 0 length' do
217
217
  it 'returns nil' do
218
218
  column = DBF::Column.new table, 'ColumnName', 'D', 0, 0
219
219
  expect(column.type_cast('')).to be_nil
@@ -232,7 +232,7 @@ RSpec.describe DBF::Column do
232
232
  expect(column.type_cast(nil)).to be_nil
233
233
  end
234
234
 
235
- context 'and 0 length' do
235
+ context 'with 0 length' do
236
236
  it 'returns nil' do
237
237
  column = DBF::Column.new table, 'ColumnName', 'M', 0, 0
238
238
  expect(column.type_cast('')).to be_nil
@@ -252,7 +252,7 @@ RSpec.describe DBF::Column do
252
252
  expect(column.type_cast(nil)).to be_nil
253
253
  end
254
254
 
255
- context 'and 0 length' do
255
+ context 'with 0 length' do
256
256
  it 'returns nil' do
257
257
  column = DBF::Column.new table, 'ColumnName', 'G', 0, 0
258
258
  expect(column.type_cast('')).to be_nil
@@ -269,14 +269,14 @@ RSpec.describe DBF::Column do
269
269
  end
270
270
 
271
271
  it 'supports negative currency' do
272
- expect(column.type_cast("\xFC\xF0\xF0\xFE\xFF\xFF\xFF\xFF")).to eq (-1776.41)
272
+ expect(column.type_cast("\xFC\xF0\xF0\xFE\xFF\xFF\xFF\xFF")).to eq(-1776.41)
273
273
  end
274
274
 
275
275
  it 'supports 64bit negative currency' do
276
- expect(column.type_cast("pN'9\xFF\xFF\xFF\xFF")).to eq (-333609.0)
276
+ expect(column.type_cast("pN'9\xFF\xFF\xFF\xFF")).to eq(-333_609.0)
277
277
  end
278
278
 
279
- context 'and 0 length' do
279
+ context 'with 0 length' do
280
280
  it 'returns nil' do
281
281
  column = DBF::Column.new table, 'ColumnName', 'Y', 0, 0
282
282
  expect(column.type_cast('')).to be_nil
@@ -284,7 +284,7 @@ RSpec.describe DBF::Column do
284
284
  end
285
285
  end
286
286
 
287
- context '#name' do
287
+ describe '#name' do
288
288
  it 'contains only ASCII characters' do
289
289
  column = DBF::Column.new table, "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--", 'N', 1, 0
290
290
  expect(column.name).to eq '---hello world---'
@@ -1,17 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.shared_examples_for 'DBF' do
4
- specify 'sum of column lengths should equal record length specified in header plus one' do
5
- header_record_length = table.instance_eval { @header.record_length }
6
- sum_of_column_lengths = table.columns.inject(1) { |sum, column| sum += column.length }
4
+ let(:header_record_length) { table.instance_eval { header.record_length } }
5
+ let(:sum_of_column_lengths) { table.columns.inject(1) { |sum, column| sum + column.length } }
7
6
 
7
+ specify 'sum of column lengths should equal record length specified in header plus one' do
8
8
  expect(header_record_length).to eq sum_of_column_lengths
9
9
  end
10
10
 
11
11
  specify 'records should be instances of DBF::Record' do
12
- table.each do |record|
13
- expect(record).to be_kind_of(DBF::Record)
14
- end
12
+ expect(table).to all be_kind_of(DBF::Record)
15
13
  end
16
14
 
17
15
  specify 'record count should be the same as reported in the header' do
@@ -20,7 +18,7 @@ RSpec.shared_examples_for 'DBF' do
20
18
 
21
19
  specify 'column names should not be blank' do
22
20
  table.columns.each do |column|
23
- expect(column.name).not_to be_empty
21
+ expect(column.name).to_not be_empty
24
22
  end
25
23
  end
26
24
 
@@ -53,17 +51,17 @@ end
53
51
  RSpec.describe DBF, 'of type 03 (dBase III without memo file)' do
54
52
  let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
55
53
 
56
- it_should_behave_like 'DBF'
54
+ it_behaves_like 'DBF'
57
55
 
58
- it 'should report the correct version number' do
56
+ it 'reports the correct version number' do
59
57
  expect(table.version).to eq '03'
60
58
  end
61
59
 
62
- it 'should report the correct version description' do
60
+ it 'reports the correct version description' do
63
61
  expect(table.version_description).to eq 'dBase III without memo file'
64
62
  end
65
63
 
66
- it 'should determine the number of records' do
64
+ it 'determines the number of records' do
67
65
  expect(table.record_count).to eq 14
68
66
  end
69
67
  end
@@ -71,17 +69,17 @@ end
71
69
  RSpec.describe DBF, 'of type 30 (Visual FoxPro)' do
72
70
  let(:table) { DBF::Table.new fixture('dbase_30.dbf') }
73
71
 
74
- it_should_behave_like 'DBF'
72
+ it_behaves_like 'DBF'
75
73
 
76
- it 'should report the correct version number' do
74
+ it 'reports the correct version number' do
77
75
  expect(table.version).to eq '30'
78
76
  end
79
77
 
80
- it 'should report the correct version description' do
78
+ it 'reports the correct version description' do
81
79
  expect(table.version_description).to eq 'Visual FoxPro'
82
80
  end
83
81
 
84
- it 'should determine the number of records' do
82
+ it 'determines the number of records' do
85
83
  expect(table.record_count).to eq 34
86
84
  end
87
85
 
@@ -93,17 +91,17 @@ end
93
91
  RSpec.describe DBF, 'of type 31 (Visual FoxPro with AutoIncrement field)' do
94
92
  let(:table) { DBF::Table.new fixture('dbase_31.dbf') }
95
93
 
96
- it_should_behave_like 'DBF'
94
+ it_behaves_like 'DBF'
97
95
 
98
- it 'should have a dBase version of 31' do
96
+ it 'has a dBase version of 31' do
99
97
  expect(table.version).to eq '31'
100
98
  end
101
99
 
102
- it 'should report the correct version description' do
100
+ it 'reports the correct version description' do
103
101
  expect(table.version_description).to eq 'Visual FoxPro with AutoIncrement field'
104
102
  end
105
103
 
106
- it 'should determine the number of records' do
104
+ it 'determines the number of records' do
107
105
  expect(table.record_count).to eq 77
108
106
  end
109
107
  end
@@ -111,17 +109,17 @@ end
111
109
  RSpec.describe DBF, 'of type 83 (dBase III with memo file)' do
112
110
  let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
113
111
 
114
- it_should_behave_like 'DBF'
112
+ it_behaves_like 'DBF'
115
113
 
116
- it 'should report the correct version number' do
114
+ it 'reports the correct version number' do
117
115
  expect(table.version).to eq '83'
118
116
  end
119
117
 
120
- it 'should report the correct version description' do
118
+ it 'reports the correct version description' do
121
119
  expect(table.version_description).to eq 'dBase III with memo file'
122
120
  end
123
121
 
124
- it 'should determine the number of records' do
122
+ it 'determines the number of records' do
125
123
  expect(table.record_count).to eq 67
126
124
  end
127
125
  end
@@ -129,17 +127,17 @@ end
129
127
  RSpec.describe DBF, 'of type 8b (dBase IV with memo file)' do
130
128
  let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
131
129
 
132
- it_should_behave_like 'DBF'
130
+ it_behaves_like 'DBF'
133
131
 
134
- it 'should report the correct version number' do
132
+ it 'reports the correct version number' do
135
133
  expect(table.version).to eq '8b'
136
134
  end
137
135
 
138
- it 'should report the correct version description' do
136
+ it 'reports the correct version description' do
139
137
  expect(table.version_description).to eq 'dBase IV with memo file'
140
138
  end
141
139
 
142
- it 'should determine the number of records' do
140
+ it 'determines the number of records' do
143
141
  expect(table.record_count).to eq 10
144
142
  end
145
143
  end
@@ -147,17 +145,17 @@ end
147
145
  RSpec.describe DBF, 'of type f5 (FoxPro with memo file)' do
148
146
  let(:table) { DBF::Table.new fixture('dbase_f5.dbf') }
149
147
 
150
- it_should_behave_like 'DBF'
148
+ it_behaves_like 'DBF'
151
149
 
152
- it 'should report the correct version number' do
150
+ it 'reports the correct version number' do
153
151
  expect(table.version).to eq 'f5'
154
152
  end
155
153
 
156
- it 'should report the correct version description' do
154
+ it 'reports the correct version description' do
157
155
  expect(table.version_description).to eq 'FoxPro with memo file'
158
156
  end
159
157
 
160
- it 'should determine the number of records' do
158
+ it 'determines the number of records' do
161
159
  expect(table.record_count).to eq 975
162
160
  end
163
161
 
@@ -6,7 +6,7 @@ RSpec.describe DBF::Record do
6
6
  let(:record_0) { YAML.load_file(fixture('dbase_83_record_0.yml')) }
7
7
  let(:record_9) { YAML.load_file(fixture('dbase_83_record_9.yml')) }
8
8
 
9
- it 'should return an ordered array of attribute values' do
9
+ it 'returns an ordered array of attribute values' do
10
10
  record = table.record(0)
11
11
  expect(record.to_a).to eq record_0
12
12
 
@@ -44,13 +44,13 @@ RSpec.describe DBF::Record do
44
44
 
45
45
  describe 'when other does not have attributes' do
46
46
  it 'returns false' do
47
- expect((record == double('other'))).to be_falsey
47
+ expect((record == instance_double('DBF::Record'))).to be_falsey
48
48
  end
49
49
  end
50
50
 
51
51
  describe 'if other attributes match' do
52
52
  let(:attributes) { {x: 1, y: 2} }
53
- let(:other) { double('object', attributes: attributes) }
53
+ let(:other) { instance_double('DBF::Record', attributes: attributes) }
54
54
 
55
55
  before do
56
56
  allow(record).to receive(:attributes).and_return(attributes)
@@ -80,11 +80,11 @@ RSpec.describe DBF::Record do
80
80
  let(:table) { DBF::Table.new fixture('cp1251.dbf') }
81
81
  let(:record) { table.find(0) }
82
82
 
83
- it 'should automatically encodes to default system encoding' do
83
+ it 'encodes to default system encoding' do
84
84
  expect(record.name.encoding).to eq Encoding.default_external
85
85
 
86
86
  # russian a
87
- expect(record.name.encode('UTF-8').unpack('H4')).to eq ['d0b0']
87
+ expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd0b0'
88
88
  end
89
89
  end
90
90
 
@@ -92,11 +92,11 @@ RSpec.describe DBF::Record do
92
92
  let(:table) { DBF::Table.new fixture('cp1251.dbf'), nil, 'cp866' }
93
93
  let(:record) { table.find(0) }
94
94
 
95
- it 'should transcode from manually specified encoding to default system encoding' do
95
+ it 'transcodes from manually specified encoding to default system encoding' do
96
96
  expect(record.name.encoding).to eq Encoding.default_external
97
97
 
98
98
  # russian а encoded in cp1251 and read as if it was encoded in cp866
99
- expect(record.name.encode('UTF-8').unpack('H4')).to eq ['d180']
99
+ expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd180'
100
100
  end
101
101
  end
102
102
  end
@@ -44,7 +44,7 @@ RSpec.describe DBF::Table do
44
44
  end
45
45
  end
46
46
 
47
- context '#close' do
47
+ describe '#close' do
48
48
  before { table.close }
49
49
 
50
50
  it 'closes the io' do
@@ -83,12 +83,12 @@ RSpec.describe DBF::Table do
83
83
  end
84
84
 
85
85
  describe '#sequel_schema' do
86
- it 'should return a valid Sequel migration by default' do
86
+ it 'returns a valid Sequel migration by default' do
87
87
  control_schema = File.read(fixture('dbase_83_schema_sq.txt'))
88
88
  expect(table.sequel_schema).to eq control_schema
89
89
  end
90
90
 
91
- it 'should return a limited Sequel migration when passed true' do
91
+ it 'returns a limited Sequel migration when passed true' do
92
92
  control_schema = File.read(fixture('dbase_83_schema_sq_lim.txt'))
93
93
  expect(table.sequel_schema).to eq control_schema
94
94
  end
@@ -129,13 +129,7 @@ RSpec.describe DBF::Table do
129
129
 
130
130
  describe 'when no path param passed' do
131
131
  it 'writes to STDOUT' do
132
- begin
133
- $stdout = StringIO.new
134
- table.to_csv
135
- expect($stdout.string).not_to be_empty
136
- ensure
137
- $stdout = STDOUT
138
- end
132
+ expect { table.to_csv }.to output.to_stdout
139
133
  end
140
134
  end
141
135
 
@@ -143,7 +137,7 @@ RSpec.describe DBF::Table do
143
137
  before { table.to_csv('test.csv') }
144
138
 
145
139
  it 'creates a custom csv file' do
146
- expect(File.exist?('test.csv')).to be_truthy
140
+ expect(File).to be_exist('test.csv')
147
141
  end
148
142
  end
149
143
  end
@@ -153,10 +147,18 @@ RSpec.describe DBF::Table do
153
147
  allow(table).to receive(:deleted_record?).and_return(true)
154
148
  expect(table.record(5)).to be_nil
155
149
  end
150
+
151
+ describe 'when dbf has no column definitions' do
152
+ let(:dbf_path) { fixture('polygon.dbf') }
153
+
154
+ it 'raises a DBF::NoColumnsDefined error' do
155
+ expect { DBF::Table.new(dbf_path).record(1) }.to raise_error(DBF::NoColumnsDefined, 'The DBF file has no columns defined')
156
+ end
157
+ end
156
158
  end
157
159
 
158
160
  describe '#current_record' do
159
- it 'should return nil for deleted records' do
161
+ it 'returns nil for deleted records' do
160
162
  allow(table).to receive(:deleted_record?).and_return(true)
161
163
  expect(table.record(0)).to be_nil
162
164
  end
@@ -201,24 +203,24 @@ RSpec.describe DBF::Table do
201
203
  expect(table.find(:all, 'WEIGHT' => 0.0)).to eq table.select { |r| r['weight'] == 0.0 }
202
204
  end
203
205
 
204
- it 'should AND multiple search terms' do
206
+ it 'ANDS multiple search terms' do
205
207
  expect(table.find(:all, 'ID' => 30, :IMAGE => 'graphics/00000001/TBC01.jpg')).to be_empty
206
208
  end
207
209
 
208
- it 'should match original column names' do
209
- expect(table.find(:all, 'WEIGHT' => 0.0)).not_to be_empty
210
+ it 'matches original column names' do
211
+ expect(table.find(:all, 'WEIGHT' => 0.0)).to_not be_empty
210
212
  end
211
213
 
212
214
  it 'matches symbolized column names' do
213
- expect(table.find(:all, :WEIGHT => 0.0)).not_to be_empty
215
+ expect(table.find(:all, WEIGHT: 0.0)).to_not be_empty
214
216
  end
215
217
 
216
218
  it 'matches downcased column names' do
217
- expect(table.find(:all, 'weight' => 0.0)).not_to be_empty
219
+ expect(table.find(:all, 'weight' => 0.0)).to_not be_empty
218
220
  end
219
221
 
220
222
  it 'matches symbolized downcased column names' do
221
- expect(table.find(:all, :weight => 0.0)).not_to be_empty
223
+ expect(table.find(:all, weight: 0.0)).to_not be_empty
222
224
  end
223
225
  end
224
226
 
@@ -276,13 +278,13 @@ RSpec.describe DBF::Table do
276
278
  let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
277
279
 
278
280
  it 'is false' do
279
- expect(table.has_memo_file?).to be_falsey
281
+ expect(table).to_not have_memo_file
280
282
  end
281
283
  end
282
284
 
283
285
  describe 'with a memo file' do
284
286
  it 'is true' do
285
- expect(table.has_memo_file?).to be_truthy
287
+ expect(table).to have_memo_file
286
288
  end
287
289
  end
288
290
  end
@@ -293,7 +295,7 @@ RSpec.describe DBF::Table do
293
295
  it 'is an array of Columns' do
294
296
  expect(columns).to be_an(Array)
295
297
  expect(columns).to_not be_empty
296
- expect(columns.all? { |c| c.class == DBF::Column }).to be_truthy
298
+ expect(columns).to be_all { |c| c.is_a? DBF::Column }
297
299
  end
298
300
  end
299
301
 
@@ -318,7 +320,7 @@ RSpec.describe DBF::Table do
318
320
  end
319
321
  end
320
322
 
321
- context '#activerecord_schema_definition' do
323
+ describe '#activerecord_schema_definition' do
322
324
  context 'with type N (number)' do
323
325
  it 'outputs an integer column' do
324
326
  column = DBF::Column.new table, 'ColumnName', 'N', 1, 0
@@ -326,7 +328,7 @@ RSpec.describe DBF::Table do
326
328
  end
327
329
  end
328
330
 
329
- context 'with type B (binary)' do
331
+ describe 'with type B (binary)' do
330
332
  context 'with Foxpro dbf' do
331
333
  it 'outputs a float column' do
332
334
  column = DBF::Column.new table, 'ColumnName', 'B', 1, 2
Binary file
@@ -4,8 +4,6 @@ begin
4
4
  rescue LoadError
5
5
  end
6
6
 
7
- Encoding.default_external = 'UTF-8'
8
-
9
7
  require 'dbf'
10
8
  require 'yaml'
11
9
  require 'rspec'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbf
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.3
4
+ version: 4.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Morrison
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-02 00:00:00.000000000 Z
11
+ date: 2020-08-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A small fast library for reading dBase, xBase, Clipper and FoxPro database
14
14
  files.
@@ -48,7 +48,7 @@ files:
48
48
  - lib/dbf/table.rb
49
49
  - lib/dbf/version.rb
50
50
  - spec/dbf/column_spec.rb
51
- - spec/dbf/database_spec.rb
51
+ - spec/dbf/database/foxpro_spec.rb
52
52
  - spec/dbf/file_formats_spec.rb
53
53
  - spec/dbf/record_spec.rb
54
54
  - spec/dbf/table_spec.rb
@@ -90,12 +90,13 @@ files:
90
90
  - spec/fixtures/foxprodb/setup.dbf
91
91
  - spec/fixtures/foxprodb/types.CDX
92
92
  - spec/fixtures/foxprodb/types.dbf
93
+ - spec/fixtures/polygon.dbf
93
94
  - spec/spec_helper.rb
94
95
  homepage: http://github.com/infused/dbf
95
96
  licenses:
96
97
  - MIT
97
98
  metadata: {}
98
- post_install_message:
99
+ post_install_message:
99
100
  rdoc_options:
100
101
  - "--charset=UTF-8"
101
102
  require_paths:
@@ -104,21 +105,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
105
  requirements:
105
106
  - - ">="
106
107
  - !ruby/object:Gem::Version
107
- version: '0'
108
+ version: 2.4.0
108
109
  required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  requirements:
110
111
  - - ">="
111
112
  - !ruby/object:Gem::Version
112
113
  version: 1.3.0
113
114
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.7.6
116
- signing_key:
115
+ rubygems_version: 3.1.2
116
+ signing_key:
117
117
  specification_version: 4
118
118
  summary: Read xBase files
119
119
  test_files:
120
+ - spec/dbf/database/foxpro_spec.rb
120
121
  - spec/dbf/file_formats_spec.rb
121
- - spec/dbf/database_spec.rb
122
122
  - spec/dbf/column_spec.rb
123
123
  - spec/dbf/record_spec.rb
124
124
  - spec/dbf/table_spec.rb