dbf 3.1.3 → 4.1.3

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.
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