dbf 1.3.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,25 @@
1
+ ## 1.5.0
2
+
3
+ - Significant internal restructuring and performance improvements. Initial
4
+ testing shows 4x faster performance.
5
+
6
+ ## 1.3.0
7
+
8
+ - Only load what's needed from activesupport 3.0
9
+ - Updatate fastercsv dependency to 1.5.3
10
+ - Remove use of 'returning' method
11
+ - Remove jeweler in favor of manual gemspec creation
12
+ - Move Table#all_values_match? to Record#match?
13
+ - Add attr_reader for Record#table
14
+ - Use method_defined? instead of respond_to? when defining attribute accessors
15
+ - Move memo file check into get_memo_header_info
16
+ - Remove unnecessary seek_to_record in Table#each
17
+ - Add rake console task
18
+ - New Attribute class
19
+ - Add a helper method for memo column type
20
+ - Move constants into the classes where they are used
21
+ - Use bundler
22
+
1
23
  ## 1.2.9
2
24
 
3
25
  - Retain trailing whitespace in memos
data/Gemfile CHANGED
@@ -1,5 +1,2 @@
1
+ gemspec
1
2
  source :rubygems
2
-
3
- gem 'activesupport', '3.0.0'
4
- gem 'i18n', '0.4.1'
5
- gem 'rspec', '1.3.0'
@@ -1,14 +1,91 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dbf (1.3.0)
5
+ activesupport (= 3.0.1)
6
+ fastercsv (= 1.5.3)
7
+
1
8
  GEM
2
9
  remote: http://rubygems.org/
3
10
  specs:
4
- activesupport (3.0.0)
5
- i18n (0.4.1)
6
- rspec (1.3.0)
11
+ Saikuro (1.1.0)
12
+ activesupport (3.0.1)
13
+ arrayfields (4.7.4)
14
+ chronic (0.2.3)
15
+ hoe (>= 1.2.1)
16
+ churn (0.0.12)
17
+ chronic (~> 0.2.3)
18
+ hirb
19
+ json_pure
20
+ main
21
+ ruby_parser (~> 2.0.4)
22
+ sexp_processor (~> 3.0.3)
23
+ colored (1.2)
24
+ diff-lcs (1.1.2)
25
+ fastercsv (1.5.3)
26
+ fattr (2.2.0)
27
+ flay (1.4.1)
28
+ ruby_parser (~> 2.0)
29
+ sexp_processor (~> 3.0)
30
+ flog (2.5.0)
31
+ ruby_parser (~> 2.0)
32
+ sexp_processor (~> 3.0)
33
+ hirb (0.3.5)
34
+ hoe (2.6.2)
35
+ rake (>= 0.8.7)
36
+ rubyforge (>= 2.0.4)
37
+ json_pure (1.4.6)
38
+ main (4.3.0)
39
+ arrayfields (>= 4.7.4)
40
+ fattr (>= 2.1.0)
41
+ metric_fu (2.0.1)
42
+ Saikuro (>= 1.1.0)
43
+ activesupport (>= 2.0.0)
44
+ chronic (~> 0.2.3)
45
+ churn (>= 0.0.7)
46
+ flay (>= 1.2.1)
47
+ flog (>= 2.2.0)
48
+ rails_best_practices (>= 0.3.16)
49
+ rcov (>= 0.8.3.3)
50
+ reek (>= 1.2.6)
51
+ roodi (>= 2.1.0)
52
+ progressbar (0.9.0)
53
+ rails_best_practices (0.5.0)
54
+ activesupport
55
+ colored (~> 1.2)
56
+ progressbar (~> 0.9.0)
57
+ ruby_parser (~> 2.0.4)
58
+ rake (0.8.7)
59
+ rcov (0.9.9)
60
+ reek (1.2.8)
61
+ ruby2ruby (~> 1.2)
62
+ ruby_parser (~> 2.0)
63
+ sexp_processor (~> 3.0)
64
+ roodi (2.1.0)
65
+ ruby_parser
66
+ rspec (2.1.0)
67
+ rspec-core (~> 2.1.0)
68
+ rspec-expectations (~> 2.1.0)
69
+ rspec-mocks (~> 2.1.0)
70
+ rspec-core (2.1.0)
71
+ rspec-expectations (2.1.0)
72
+ diff-lcs (~> 1.1.2)
73
+ rspec-mocks (2.1.0)
74
+ ruby2ruby (1.2.5)
75
+ ruby_parser (~> 2.0)
76
+ sexp_processor (~> 3.0)
77
+ ruby_parser (2.0.5)
78
+ sexp_processor (~> 3.0)
79
+ rubyforge (2.0.4)
80
+ json_pure (>= 1.1.7)
81
+ sexp_processor (3.0.5)
7
82
 
8
83
  PLATFORMS
9
84
  ruby
10
85
 
11
86
  DEPENDENCIES
12
- activesupport (= 3.0.0)
13
- i18n (= 0.4.1)
14
- rspec (= 1.3.0)
87
+ activesupport (= 3.0.1)
88
+ dbf!
89
+ fastercsv (= 1.5.3)
90
+ metric_fu (= 2.0.1)
91
+ rspec (= 2.1.0)
data/README.md CHANGED
@@ -4,14 +4,14 @@ DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro
4
4
  database files
5
5
 
6
6
  * Project page: <http://github.com/infused/dbf>
7
- * API Documentation: <http://rdoc.info/projects/infused/dbf>
7
+ * API Documentation: <http://rubydoc.info/github/infused/dbf/frames>
8
8
  * Report bugs: <http://github.com/infused/dbf/issues>
9
9
  * Questions: Email <mailto:keithm@infused.org> and put DBF somewhere in the
10
10
  subject line
11
11
 
12
12
  ## Compatibility
13
13
 
14
- DBF is tested to work with Ruby 1.8.6, 1.8.7, 1.9.1 and 1.9.2
14
+ DBF works with Ruby 1.8.6, 1.8.7, and 1.9.2
15
15
 
16
16
  ## Installation
17
17
 
@@ -23,46 +23,45 @@ Load a DBF file:
23
23
 
24
24
  require 'dbf'
25
25
 
26
- table = DBF::Table.new("widgets.dbf")
26
+ widgets = DBF::Table.new("widgets.dbf")
27
27
 
28
28
  Enumerate all records
29
29
 
30
- table.each do |record|
31
- puts record.name
32
- puts record.email
30
+ widgets.each do |record|
31
+ puts widget.name
32
+ puts widget.email
33
33
  end
34
34
 
35
- Load a single record using <tt>record</tt> or <tt>find</tt>
35
+ Load a single record using <tt>find</tt>
36
36
 
37
- table.record(6)
38
- table.find(6)
37
+ widget.find(6)
39
38
 
40
39
  Attributes can also be accessed through the attributes hash in original or
41
40
  underscored form or as an accessor method using the underscored name. (Note
42
- that record() will return nil if the requested record has been deleted and not
41
+ that find() will return nil if the requested record has been deleted and not
43
42
  yet pruned from the database)
44
43
 
45
- table.record(4).attributes["PhoneBook"]
46
- table.record(4).attributes["phone_book"]
47
- table.record(4).phone_book
44
+ widget.find(4).attributes["SlotNumber"]
45
+ widget.find(4).attributes["slot_number"]
46
+ widget.find(4).slot_number
48
47
 
49
48
  Search for records using a simple hash format. Multiple search criteria are
50
49
  ANDed. Use the block form if the resulting recordset could be large, otherwise
51
50
  all records will be loaded into memory.
52
51
 
53
- # find all records with first_name equal to Keith
54
- table.find(:all, :first_name => 'Keith') do |record|
52
+ # find all records with slot_number equal to s42
53
+ widgets.find(:all, :slot_number => 's42') do |widget|
55
54
  # the record will be nil if deleted, but not yet pruned from the database
56
- if record
57
- puts record.last_name
55
+ if widget
56
+ puts widget.serial_number
58
57
  end
59
58
  end
60
59
 
61
- # find the first record with first_name equal to Keith
62
- table.find :first, :first_name => 'Keith'
60
+ # find the first record with slot_number equal to s42
61
+ widgets.find :first, :slot_number => 's42'
63
62
 
64
63
  # find record number 10
65
- table.find(10)
64
+ widgets.find(10)
66
65
 
67
66
  ## Migrating to ActiveRecord
68
67
 
@@ -100,7 +99,7 @@ A small command-line utility called dbf is installed along with the gem.
100
99
 
101
100
  The basic dBase data types are generally supported well. Support for the
102
101
  advanced data types in dbase V and FoxPro are still experimental or not
103
- supported. If you have insight into how any of unsupported data types are
102
+ supported. If you have insight into how any of the unsupported data types are
104
103
  implemented, please give me a shout. FoxBase/dBase II files are not supported
105
104
  at this time.
106
105
 
data/Rakefile CHANGED
@@ -1,42 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'rubygems'
4
- require 'rubygems/specification'
5
4
 
6
- def gemspec
7
- @gemspec ||= begin
8
- file = File.expand_path('../dbf.gemspec', __FILE__)
9
- eval(File.read(file), binding, file)
10
- end
11
- end
12
-
13
- begin
14
- require 'rake/gempackagetask'
15
- rescue LoadError
16
- task(:gem) { $stderr.puts '`gem install rake` to package gems' }
17
- else
18
- Rake::GemPackageTask.new(gemspec) do |pkg|
19
- pkg.gem_spec = gemspec
20
- end
21
- task :gem => :gemspec
22
- end
23
-
24
- begin
25
- require 'spec/rake/spectask'
26
- rescue LoadError
27
- raise 'Run `gem install rspec` to be able to run specs'
28
- else
29
- task :clear_tmp do
30
- FileUtils.rm_rf(File.expand_path("../tmp", __FILE__))
31
- end
32
-
33
- desc "Run specs"
34
- Spec::Rake::SpecTask.new do |t|
35
- t.spec_files = FileList['spec/**/*_spec.rb']
36
- t.spec_opts = %w(-fs --color)
37
- t.warning = true
38
- end
39
- task :spec
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new :spec do |t|
7
+ t.rspec_opts = %w(-fs --color)
40
8
  end
41
9
 
42
10
  require 'rake'
@@ -49,20 +17,15 @@ Rake::RDocTask.new { |rdoc|
49
17
  rdoc.rdoc_files.include('README.md', 'docs/supported_types.markdown', 'lib/**/*.rb')
50
18
  }
51
19
 
52
- desc "install the gem locally"
53
- task :install => :package do
54
- sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
55
- end
56
-
57
- desc "validate the gemspec"
58
- task :gemspec do
59
- gemspec.validate
60
- end
61
-
62
- task :package => :gemspec
63
20
  task :default => :spec
64
21
 
65
22
  desc "Open an irb session preloaded with this library"
66
23
  task :console do
67
24
  sh "irb -rubygems -I lib -r dbf.rb"
25
+ end
26
+
27
+ require 'metric_fu'
28
+ MetricFu::Configuration.run do |config|
29
+ config.rcov[:test_files] = ['spec/**/*_spec.rb']
30
+ config.rcov[:rcov_opts] << "-Ispec"
68
31
  end
data/bin/dbf CHANGED
File without changes
data/lib/dbf.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'date'
2
- gem 'activesupport', '=3.0.0'
2
+ gem 'activesupport'
3
3
  require 'active_support/core_ext/object'
4
4
  require 'active_support/core_ext/date/conversions'
5
5
  require 'active_support/core_ext/time/conversions'
@@ -7,20 +7,15 @@ require 'active_support/core_ext/date_time/conversions'
7
7
  require 'active_support/core_ext/string/conversions'
8
8
  require 'active_support/core_ext/module/delegation'
9
9
  require 'active_support/core_ext/string/inflections'
10
+ require 'active_support/core_ext/enumerable'
10
11
 
11
- if RUBY_VERSION > '1.9'
12
- require 'csv'
13
- unless defined? FCSV
14
- class Object
15
- FCSV = CSV
16
- alias_method :FCSV, :CSV
17
- end
18
- end
19
- else
20
- require 'fastercsv'
12
+ require 'csv'
13
+ if CSV.const_defined? :Reader
14
+ require 'fastercsv'
21
15
  end
22
16
 
23
17
  require 'dbf/attributes'
24
18
  require 'dbf/record'
25
19
  require 'dbf/column'
20
+ require 'dbf/memo'
26
21
  require 'dbf/table'
@@ -14,7 +14,7 @@ module DBF
14
14
  # @param [Fixnum] length
15
15
  # @param [Fixnum] decimal
16
16
  def initialize(name, type, length, decimal)
17
- @name, @type, @length, @decimal = strip_non_ascii_chars(name), type, length, decimal
17
+ @name, @type, @length, @decimal = clean(name), type, length, decimal
18
18
 
19
19
  raise ColumnLengthError, "field length must be greater than 0" unless length > 0
20
20
  raise ColumnNameError, "column name cannot be empty" if @name.length == 0
@@ -26,95 +26,67 @@ module DBF
26
26
  # @return [Fixnum, Float, Date, DateTime, Boolean, String]
27
27
  def type_cast(value)
28
28
  case type
29
- when 'N' # number
30
- unpack_number(value)
31
- when 'I' # integer
32
- unpack_unsigned_long(value)
33
- when 'F' # float
34
- unpack_float(value)
35
- when 'D' # date
36
- decode_date(value)
37
- when 'T' # datetime
38
- decode_datetime(value)
39
- when 'L' # logical
40
- boolean(value)
41
- else
42
- value.to_s.strip
29
+ when 'N' then unpack_number(value)
30
+ when 'I' then unpack_unsigned_long(value)
31
+ when 'F' then unpack_float(value)
32
+ when 'D' then decode_date(value)
33
+ when 'T' then decode_datetime(value)
34
+ when 'L' then boolean(value)
35
+ else value.to_s.strip
43
36
  end
44
37
  end
45
38
 
46
- # Decode a Date value
39
+ def memo?
40
+ @memo ||= type == 'M'
41
+ end
42
+
43
+ # Schema definition
47
44
  #
48
- # @param [String] value
49
- # @return [Date]
50
- def decode_date(value)
51
- return nil if value.blank?
52
- value.is_a?(String) ? value.gsub(' ', '0').to_date : value.to_date
45
+ # @return [String]
46
+ def schema_definition
47
+ "\"#{name.underscore}\", #{schema_data_type}\n"
48
+ end
49
+
50
+ def underscored_name
51
+ @underscored_name ||= name.underscore
52
+ end
53
+
54
+ private
55
+
56
+ def decode_date(value) #nodoc
57
+ value.gsub!(' ', '0')
58
+ value.blank? ? nil : value.to_date
53
59
  rescue
54
60
  nil
55
61
  end
56
62
 
57
- # Decode a DateTime value
58
- #
59
- # @param [String] value
60
- # @return [DateTime]
61
- def decode_datetime(value)
63
+ def decode_datetime(value) #nodoc
62
64
  days, milliseconds = value.unpack('l2')
63
65
  seconds = milliseconds / 1000
64
66
  DateTime.jd(days, seconds/3600, seconds/60 % 60, seconds % 60) rescue nil
65
67
  end
66
68
 
67
- # Decode a number value
68
- #
69
- # @param [String] value
70
- # @return [Fixnum, Float]
71
- def unpack_number(value)
69
+ def unpack_number(value) #nodoc
72
70
  decimal.zero? ? unpack_integer(value) : value.to_f
73
71
  end
74
72
 
75
- # Decode a float value
76
- #
77
- # @param [String] value
78
- # @return [Float]
79
- def unpack_float(value)
73
+ def unpack_float(value) #nodoc
80
74
  value.to_f
81
75
  end
82
76
 
83
- # Decode an integer
84
- #
85
- # @param [String] value
86
- # @return [Fixnum]
87
- def unpack_integer(value)
77
+ def unpack_integer(value) #nodoc
88
78
  value.to_i
89
79
  end
90
80
 
91
- # Decode an unsigned long
92
- #
93
- # @param [String] value
94
- # @return [Fixnum]
95
- def unpack_unsigned_long(value)
81
+ def unpack_unsigned_long(value) #nodoc
96
82
  value.unpack('V')[0]
97
83
  end
98
84
 
99
- # Decode a boolean value
100
- #
101
- # @param [String] value
102
- # @return [Boolean]
103
- def boolean(value)
85
+ def boolean(value) #nodoc
104
86
  value.strip =~ /^(y|t)$/i ? true : false
105
87
  end
106
88
 
107
- # Schema definition
108
- #
109
- # @return [String]
110
- def schema_definition
111
- "\"#{name.underscore}\", #{schema_data_type}\n"
112
- end
113
-
114
- # Column type for schema definition
115
- #
116
- # @return [String]
117
- def schema_data_type
89
+ def schema_data_type #nodoc
118
90
  case type
119
91
  when "N", "F"
120
92
  decimal > 0 ? ":float" : ":integer"
@@ -133,20 +105,12 @@ module DBF
133
105
  end
134
106
  end
135
107
 
136
- # Strip all non-ascii and non-printable characters
137
- #
138
- # @param [String] s
139
- # @return [String]
140
- def strip_non_ascii_chars(s)
141
- # truncate the string at the first null character
142
- s = s[0, s.index("\x00")] if s.index("\x00")
143
-
144
- s.gsub(/[^\x20-\x7E]/,"")
108
+ def clean(s) #nodoc
109
+ first_null = s.index("\x00")
110
+ s = s[0, first_null] if first_null
111
+ s.gsub(/[^\x20-\x7E]/, "")
145
112
  end
146
113
 
147
- def memo?
148
- type == 'M'
149
- end
150
114
  end
151
115
 
152
116
  end