dbf 1.0.2 → 1.0.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.
@@ -1,3 +1,6 @@
1
+ == 1.0.3
2
+ * Add support for Visual Foxpro Integer and Datetime columns
3
+
1
4
  == 1.0.2
2
5
 
3
6
  * Compatibility fix for Visual Foxpro memo files (ignore negative memo index values)
@@ -10,6 +13,9 @@
10
13
 
11
14
  * Renamed classes and refactored code in preparation for adding the
12
15
  ability to save records and create/compact databases.
16
+ * The Reader class has been renamed to Table
17
+ * Attributes are no longer accessed directly from the record. Use record.attribute['column_name']
18
+ instead, or use the new attribute accessors detailed under Basic Usage.
13
19
 
14
20
  == 0.5.4
15
21
 
data/README.txt CHANGED
@@ -49,6 +49,27 @@ Copyright (c) 2006-2007 Keith Morrison <keithm@infused.org, www.infused.org>
49
49
  table.find :first, :first_name => 'Keith'
50
50
  table.find(10)
51
51
 
52
+ == Migrating to ActiveRecord
53
+
54
+ An example of migrating a DBF book table to ActiveRecord using a migration:
55
+
56
+ require 'dbf'
57
+
58
+ class CreateBooks < ActiveRecord::Migration
59
+ def self.up
60
+ table = DBF::Table.new('db/dbf/books.dbf')
61
+ eval(table.schema)
62
+
63
+ table.records.each do |record|
64
+ Book.create(record.attributes)
65
+ end
66
+ end
67
+
68
+ def self.down
69
+ drop_table :books
70
+ end
71
+ end
72
+
52
73
  == Large databases
53
74
 
54
75
  DBF::Table defaults to loading all records into memory. This may not be what
@@ -66,12 +87,6 @@ A small command-line utility called dbf is installed along with the gem.
66
87
  -h = print this message
67
88
  -s = print summary information
68
89
  -a = create an ActiveRecord::Schema
69
-
70
- == Changes from 0.5.x
71
-
72
- * The Reader class has been renamed to Table
73
- * Attributes are no longer accessed directly from the record. Use record.attribute['column_name']
74
- instead, or use the new attribute accessors detailed under Basic Usage.
75
90
 
76
91
  == Limitations and known bugs
77
92
 
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'hoe'
2
2
  require 'spec/rake/spectask'
3
3
 
4
4
  PKG_NAME = "dbf"
5
- PKG_VERSION = "1.0.2"
5
+ PKG_VERSION = "1.0.3"
6
6
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
7
7
 
8
8
  Hoe.new PKG_NAME, PKG_VERSION do |p|
@@ -18,5 +18,9 @@ module DBF
18
18
  "fb" => "FoxPro without memo file"
19
19
  }
20
20
 
21
+ MS_PER_SECOND = 1000
22
+ MS_PER_MINUTE = MS_PER_SECOND * 60
23
+ MS_PER_HOUR = MS_PER_MINUTE * 60
24
+
21
25
  class DBFError < StandardError; end
22
26
  end
@@ -48,6 +48,10 @@ module DBF
48
48
  @attributes[column.name] = read_memo(starting_block)
49
49
  when 'L' # logical
50
50
  @attributes[column.name] = unpack_string(column) =~ /^(y|t)$/i ? true : false
51
+ when 'I' # integer
52
+ @attributes[column.name] = unpack_integer(column)
53
+ when 'T' # datetime
54
+ @attributes[column.name] = unpack_datetime(column)
51
55
  else
52
56
  @attributes[column.name] = unpack_string(column).strip
53
57
  end
@@ -61,9 +65,21 @@ module DBF
61
65
  def unpack_string(column)
62
66
  unpack_column(column).to_s
63
67
  end
68
+
69
+ def unpack_integer(column)
70
+ @data.read(column.length).unpack("v").first
71
+ end
72
+
73
+ def unpack_datetime(column)
74
+ days, milliseconds = @data.read(column.length).unpack('l2')
75
+ hours = (milliseconds / MS_PER_HOUR).to_i
76
+ minutes = ((milliseconds - (hours * MS_PER_HOUR)) / MS_PER_MINUTE).to_i
77
+ seconds = ((milliseconds - (hours * MS_PER_HOUR) - (minutes * MS_PER_MINUTE)) / MS_PER_SECOND).to_i
78
+ DateTime.jd(days, hours, minutes, seconds)
79
+ end
64
80
 
65
81
  def read_memo(start_block)
66
- return nil if start_block <= 0
82
+ return nil if start_block <= 0 || @table.memo_block_size.nil?
67
83
  @memo.seek(start_block * @table.memo_block_size)
68
84
  if @table.memo_file_format == :fpt
69
85
  memo_type, memo_size, memo_string = @memo.read(@table.memo_block_size).unpack("NNa56")
@@ -1,6 +1,15 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
3
  describe DBF::Record, "when initialized" do
4
+
5
+ def standalone_record(binary_data)
6
+ table = mock
7
+ table.stubs(:data)
8
+ table.data.stubs(:read).returns(binary_data)
9
+ table.stubs(:memo).returns(nil)
10
+ table.stubs(:columns).returns([])
11
+ DBF::Record.new(table)
12
+ end
4
13
 
5
14
  it "should typecast number columns with decimals == 0 to Integer" do
6
15
  table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
@@ -27,5 +36,21 @@ describe DBF::Record, "when initialized" do
27
36
  table.column("WEBINCLUDE").type.should == "L"
28
37
  table.records.all? {|record| record.attributes["WEBINCLUDE"].should satisfy {|v| v == true || v == false}}
29
38
  end
39
+
40
+ it "should typecast datetime columns to DateTime" do
41
+ binary_data = "Nl%\000\300Z\252\003"
42
+ record = standalone_record(binary_data)
43
+ column = stub(:length => 8)
44
+
45
+ record.instance_eval {unpack_datetime(column)}.to_s.should == "2002-10-10T17:04:56+00:00"
46
+ end
47
+
48
+ it "should typecast integers to Fixnum" do
49
+ binary_data = "\017\020\000\000"
50
+ record = standalone_record(binary_data)
51
+ column = stub(:length => 4)
52
+
53
+ record.instance_eval {unpack_integer(column)}.should == 4111
54
+ end
30
55
 
31
56
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: dbf
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.2
7
- date: 2007-08-14 00:00:00 -07:00
6
+ version: 1.0.3
7
+ date: 2007-09-02 00:00:00 -07:00
8
8
  summary: A small fast library for reading dBase, xBase, Clipper and FoxPro database files.
9
9
  require_paths:
10
10
  - lib
@@ -85,5 +85,5 @@ dependencies:
85
85
  requirements:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: 1.2.2
88
+ version: 1.3.0
89
89
  version: