dbf 1.0.3 → 1.0.5

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.
data/History.txt CHANGED
@@ -1,4 +1,13 @@
1
+ == 1.0.5
2
+
3
+ * Strip non-ascii characters from column names
4
+
5
+ == 1.0.4
6
+
7
+ * Underscore column names when dumping schemas (FieldId becomes field_id)
8
+
1
9
  == 1.0.3
10
+
2
11
  * Add support for Visual Foxpro Integer and Datetime columns
3
12
 
4
13
  == 1.0.2
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.3"
5
+ PKG_VERSION = "1.0.5"
6
6
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
7
7
 
8
8
  Hoe.new PKG_NAME, PKG_VERSION do |p|
data/lib/dbf/column.rb CHANGED
@@ -6,7 +6,47 @@ module DBF
6
6
 
7
7
  def initialize(name, type, length, decimal)
8
8
  raise ColumnLengthError, "field length must be greater than 0" unless length > 0
9
- @name, @type, @length, @decimal = name.gsub(/\0/, ''), type, length, decimal
9
+ @name, @type, @length, @decimal = strip_non_ascii_chars(name), type, length, decimal
10
+ end
11
+
12
+ def schema_definition
13
+ "\"#{underscore(name)}\", " +
14
+ case type
15
+ when "N" # number
16
+ if decimal > 0
17
+ ":float"
18
+ else
19
+ ":integer"
20
+ end
21
+ when "D" # date
22
+ ":datetime"
23
+ when "L" # boolean
24
+ ":boolean"
25
+ when "M" # memo
26
+ ":text"
27
+ else
28
+ ":string, :limit => #{length}"
29
+ end +
30
+ "\n"
31
+ end
32
+
33
+ private
34
+
35
+ def underscore(camel_cased_word)
36
+ camel_cased_word.to_s.gsub(/::/, '/').
37
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
38
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
39
+ tr("-", "_").
40
+ downcase
41
+ end
42
+
43
+ def strip_non_ascii_chars(s)
44
+ clean = ''
45
+ s.each_byte do |char|
46
+ clean << char if char > 31 && char < 128
47
+ end
48
+ clean
10
49
  end
11
50
  end
51
+
12
52
  end
data/lib/dbf/globals.rb CHANGED
@@ -23,4 +23,6 @@ module DBF
23
23
  MS_PER_HOUR = MS_PER_MINUTE * 60
24
24
 
25
25
  class DBFError < StandardError; end
26
+ class InvalidColumnName < DBFError; end
27
+ class InvalidColumnLength < DBFError; end
26
28
  end
data/lib/dbf/record.rb CHANGED
@@ -29,31 +29,30 @@ module DBF
29
29
 
30
30
  def initialize_values(columns)
31
31
  columns.each do |column|
32
- case column.type
32
+ @attributes[column.name] = case column.type
33
33
  when 'N' # number
34
- @attributes[column.name] = column.decimal.zero? ? unpack_string(column).to_i : unpack_string(column).to_f
34
+ column.decimal.zero? ? unpack_string(column).to_i : unpack_string(column).to_f
35
35
  when 'D' # date
36
36
  raw = unpack_string(column).strip
37
37
  unless raw.empty?
38
+ parts = raw.match(DATE_REGEXP).captures.map {|n| n.to_i}
38
39
  begin
39
- parts = raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}
40
- @attributes[column.name] = Time.gm(*parts)
40
+ Time.gm(*parts)
41
41
  rescue
42
- parts = raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}
43
- @attributes[column.name] = Date.new(*parts)
42
+ Date.new(*parts)
44
43
  end
45
44
  end
46
45
  when 'M' # memo
47
46
  starting_block = unpack_string(column).to_i
48
- @attributes[column.name] = read_memo(starting_block)
47
+ read_memo(starting_block)
49
48
  when 'L' # logical
50
- @attributes[column.name] = unpack_string(column) =~ /^(y|t)$/i ? true : false
49
+ unpack_string(column) =~ /^(y|t)$/i ? true : false
51
50
  when 'I' # integer
52
- @attributes[column.name] = unpack_integer(column)
51
+ unpack_integer(column)
53
52
  when 'T' # datetime
54
- @attributes[column.name] = unpack_datetime(column)
53
+ unpack_datetime(column)
55
54
  else
56
- @attributes[column.name] = unpack_string(column).strip
55
+ unpack_string(column).strip
57
56
  end
58
57
  end
59
58
  end
data/lib/dbf/table.rb CHANGED
@@ -105,19 +105,15 @@ module DBF
105
105
  # for the record to be returned. The equivalent SQL would be "WHERE key1 = 'value1'
106
106
  # AND key2 = 'value2'".
107
107
  def find(command, options = {})
108
+ results = options.empty? ? records : records.select {|record| all_values_match?(record, options)}
109
+
108
110
  case command
109
111
  when Fixnum
110
112
  record(command)
111
113
  when :all
112
- return records if options.empty?
113
- records.select do |record|
114
- options.map {|key, value| record.attributes[key.to_s] == value}.all?
115
- end
114
+ results
116
115
  when :first
117
- return records.first if options.empty?
118
- records.detect do |record|
119
- options.map {|key, value| record.attributes[key.to_s] == value}.all?
120
- end
116
+ results.first
121
117
  end
122
118
  end
123
119
 
@@ -151,24 +147,7 @@ module DBF
151
147
  s = "ActiveRecord::Schema.define do\n"
152
148
  s << " create_table \"#{File.basename(@data.path, ".*")}\" do |t|\n"
153
149
  columns.each do |column|
154
- s << " t.column \"#{column.name}\""
155
- case column.type
156
- when "N" # number
157
- if column.decimal > 0
158
- s << ", :float"
159
- else
160
- s << ", :integer"
161
- end
162
- when "D" # date
163
- s << ", :datetime"
164
- when "L" # boolean
165
- s << ", :boolean"
166
- when "M" # memo
167
- s << ", :text"
168
- else
169
- s << ", :string, :limit => #{column.length}"
170
- end
171
- s << "\n"
150
+ s << " t.column #{column.schema_definition}"
172
151
  end
173
152
  s << " end\nend"
174
153
 
@@ -206,8 +185,8 @@ module DBF
206
185
  @columns = []
207
186
  @column_count.times do
208
187
  name, type, length, decimal = @data.read(32).unpack('a10 x a x4 C2')
209
- if length > 0 && name.strip.any?
210
- @columns << Column.new(name, type, length, decimal)
188
+ if length > 0
189
+ @columns << Column.new(name.strip, type, length, decimal)
211
190
  end
212
191
  end
213
192
  # Reset the column count
@@ -263,6 +242,10 @@ module DBF
263
242
  end
264
243
  end
265
244
  end
245
+
246
+ def all_values_match?(record, options)
247
+ options.map {|key, value| record.attributes[key.to_s] == value}.all?
248
+ end
266
249
  end
267
250
 
268
251
  end
@@ -1,19 +1,19 @@
1
1
  ActiveRecord::Schema.define do
2
2
  create_table "dbase_83" do |t|
3
- t.column "ID", :integer
4
- t.column "CATCOUNT", :integer
5
- t.column "AGRPCOUNT", :integer
6
- t.column "PGRPCOUNT", :integer
7
- t.column "ORDER", :integer
8
- t.column "CODE", :string, :limit => 50
9
- t.column "NAME", :string, :limit => 100
10
- t.column "THUMBNAIL", :string, :limit => 254
11
- t.column "IMAGE", :string, :limit => 254
12
- t.column "PRICE", :float
13
- t.column "COST", :float
14
- t.column "DESC", :text
15
- t.column "WEIGHT", :float
16
- t.column "TAXABLE", :boolean
17
- t.column "ACTIVE", :boolean
3
+ t.column "id", :integer
4
+ t.column "catcount", :integer
5
+ t.column "agrpcount", :integer
6
+ t.column "pgrpcount", :integer
7
+ t.column "order", :integer
8
+ t.column "code", :string, :limit => 50
9
+ t.column "name", :string, :limit => 100
10
+ t.column "thumbnail", :string, :limit => 254
11
+ t.column "image", :string, :limit => 254
12
+ t.column "price", :float
13
+ t.column "cost", :float
14
+ t.column "desc", :text
15
+ t.column "weight", :float
16
+ t.column "taxable", :boolean
17
+ t.column "active", :boolean
18
18
  end
19
19
  end
@@ -26,8 +26,8 @@ describe DBF::Column, "when initialized" do
26
26
  lambda { column = DBF::Column.new "ColumnName", "N", -1, 0 }.should raise_error(DBF::ColumnLengthError)
27
27
  end
28
28
 
29
- it "should strip null characters from the name" do
30
- column = DBF::Column.new "Column\0Name\0", "N", 1, 0
29
+ it "should strip non-ascii characters from the name" do
30
+ column = DBF::Column.new "Col\200umn\0Name\037", "N", 1, 0
31
31
  column.name.should == "ColumnName"
32
32
  end
33
33
 
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.3
7
- date: 2007-09-02 00:00:00 -07:00
6
+ version: 1.0.5
7
+ date: 2007-11-27 00:00:00 -08:00
8
8
  summary: A small fast library for reading dBase, xBase, Clipper and FoxPro database files.
9
9
  require_paths:
10
10
  - lib