dbf 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: