shapelib 0.7.2 → 0.8.0

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/Rakefile CHANGED
@@ -1,48 +1,157 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rubygems'
2
4
  require 'rake'
3
- require 'jeweler'
4
- $LOAD_PATH << File.expand_path('lib')
5
-
6
- begin
7
- require 'shapelib/version'
8
- Jeweler::Tasks.new do |gem|
9
- gem.name = "shapelib"
10
- gem.summary = %Q{Simple wrapper around the shapelib library}
11
- gem.description = gem.summary
12
- gem.email = %q{nick@nickstoys.com}
13
- gem.homepage = "http://github.com/mperham/shapelib"
14
- gem.authors = ["prasinos@users.sourceforge.net", "Mike Mangino", "Mike Perham", "Nick Estes"]
15
- gem.add_development_dependency 'rake-compiler', '>= 0.7.0'
16
- gem.has_rdoc = false
17
- gem.version = Shapelib::VERSION
18
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
5
+ require 'open3'
6
+ require 'tmpdir'
7
+ require 'rbconfig'
8
+ require 'shellwords'
9
+ require 'rake/clean'
10
+ require 'rake/testtask'
11
+ require 'rubygems/package_task'
12
+
13
+ desc 'Build with Clang in C23 mode and run the tests in isolation'
14
+ task 'c23-test' do
15
+ root = __dir__
16
+ compiler = ENV.fetch('CC', 'clang')
17
+ flags = "#{ENV.fetch('CFLAGS', RbConfig::CONFIG['CFLAGS'])} -std=gnu2x"
18
+ make = Shellwords.split(ENV['MAKE'] || RbConfig::CONFIG['MAKE'] || 'make')
19
+ tests = Dir.glob(File.join(root, 'test/**/test_*.rb')).sort
20
+ abort 'c23-test: no test files found.' if tests.empty?
21
+
22
+ build_dir = Dir.mktmpdir('shapelib-c23-')
23
+ puts "C23 compiler: #{compiler}"
24
+ puts "C23 build directory: #{build_dir}"
25
+ configure = <<~'RUBY'
26
+ require 'rbconfig'
27
+ RbConfig::MAKEFILE_CONFIG['CC'] = RbConfig::CONFIG['CC'] = ARGV.shift
28
+ $0 = ARGV.shift
29
+ load $0
30
+ RUBY
31
+ Dir.chdir(build_dir) do
32
+ sh Gem.ruby, '-e', configure, compiler,
33
+ File.join(root, 'ext/shapelib_ext/extconf.rb'), "--with-cflags=#{flags}"
34
+ sh(*make)
19
35
  end
20
- Jeweler::GemcutterTasks.new
21
- rescue LoadError => le
22
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler: #{le.message}"
36
+ binary = File.join(build_dir, "shapelib_ext.#{RbConfig::CONFIG['DLEXT']}")
37
+ abort 'c23-test: the isolated extension was not built.' unless File.file?(binary)
38
+ sh Gem.ruby, "-I#{build_dir}", "-I#{File.join(root, 'lib')}", "-I#{File.join(root, 'test')}",
39
+ '-e', 'ARGV.each { |file| require File.expand_path(file) }', *tests
40
+ end
41
+
42
+ desc 'Build and test every installed RVM Ruby, with a results table and logs'
43
+ task 'rvm-test' do
44
+ root = __dir__
45
+ env = ENV.keys.grep(/\ABUNDLE_/).to_h { |key| [key, nil] }
46
+ env['RUBYOPT'] = nil
47
+ env['RUBYLIB'] = nil
48
+
49
+ begin
50
+ output, error, status = Open3.capture3(env, 'rvm', 'list', 'strings')
51
+ rescue Errno::ENOENT
52
+ abort 'rvm-test: RVM is not installed or its executable is not on PATH.'
53
+ end
54
+ abort "rvm-test: unable to list installed Rubies: #{error.strip}" unless status.success?
55
+ versions = output.lines.map(&:strip).reject(&:empty?).uniq.sort
56
+ abort 'rvm-test: no installed RVM Rubies found.' if versions.empty?
57
+ tests = Dir.glob(File.join(root, 'test/**/test_*.rb')).sort
58
+ abort 'rvm-test: no test files found.' if tests.empty?
59
+
60
+ logs = Dir.mktmpdir('shapelib-rvm-test-')
61
+ results = []
62
+ versions.each_with_index do |version, index|
63
+ puts "Testing #{version} (#{index + 1}/#{versions.length})..."
64
+ build_dir = File.join(logs, "build-#{index + 1}")
65
+ Dir.mkdir(build_dir)
66
+ run = lambda do |log, directory, *command|
67
+ system(env, 'rvm', version, 'do', *command, chdir: directory, out: log, err: %i[child out])
68
+ rescue SystemCallError => e
69
+ log.puts e.message
70
+ false
71
+ end
72
+
73
+ built = File.open(File.join(logs, "#{version}-build.log"), 'w') do |log|
74
+ run.call(log, build_dir, 'ruby', File.join(root, 'ext/shapelib_ext/extconf.rb')) && run.call(log, build_dir, 'make')
75
+ end
76
+ passed = if built
77
+ File.open(File.join(logs, "#{version}-test.log"), 'w') do |log|
78
+ run.call(log, root, 'ruby', "-I#{build_dir}", "-I#{File.join(root, 'lib')}", "-I#{File.join(root, 'test')}", '-e', 'ARGV.each { |file| require File.expand_path(file) }', *tests)
79
+ end
80
+ end
81
+ results << [version, built ? 'PASS' : 'FAIL', if built
82
+ passed ? 'PASS' : 'FAIL'
83
+ else
84
+ 'SKIPPED'
85
+ end]
86
+ end
87
+
88
+ width = [4, *versions.map(&:length)].max
89
+ puts
90
+ puts format("%-#{width}s %-5s %s", 'Ruby', 'Build', 'Tests')
91
+ results.each { |row| puts format("%-#{width}s %-5s %s", *row) }
92
+ puts "Logs and isolated builds: #{logs}"
93
+ abort 'rvm-test: one or more versions failed; see the logs above.' if results.any? do |row|
94
+ row[1..2] != %w[PASS PASS]
95
+ end
96
+ end
97
+
98
+ spec = Gem::Specification.load(File.expand_path('shapelib.gemspec', __dir__))
99
+ abort 'Unable to load shapelib.gemspec' unless spec
100
+ Gem::PackageTask.new(spec) {}
101
+
102
+ desc 'Run tests, package the gem, and push it to RubyGems.org'
103
+ task release: %i[test gem] do
104
+ sh Gem.ruby, '-S', 'gem', 'push', File.join('pkg', spec.file_name)
23
105
  end
24
106
 
25
- require 'rake/testtask'
26
107
  Rake::TestTask.new(:test) do |test|
27
- test.libs = %w(lib test)
108
+ test.libs = %w[lib test]
28
109
  test.pattern = 'test/**/test_*.rb'
29
110
  test.verbose = true
30
111
  end
31
112
 
32
- task :test => :check_dependencies
33
- task :default => :test
113
+ task test: :compile
114
+ task default: :test
115
+
116
+ build_dir = File.join('tmp', RUBY_PLATFORM, 'shapelib_ext', RUBY_VERSION)
117
+ extconf = File.expand_path('ext/shapelib_ext/extconf.rb', __dir__)
118
+ makefile = File.join(build_dir, 'Makefile')
119
+ binary = "shapelib_ext.#{RbConfig::CONFIG['DLEXT']}"
34
120
 
35
- #require 'rake/rdoctask'
36
- require 'rdoc/task'
37
- Rake::RDocTask.new do |rdoc|
38
- rdoc.rdoc_dir = 'rdoc'
39
- rdoc.title = "shapelib"
40
- rdoc.rdoc_files.include('README*')
41
- rdoc.rdoc_files.include('lib/**/*.rb')
121
+ file makefile => [extconf] do
122
+ mkdir_p build_dir
123
+ Dir.chdir(build_dir) { sh Gem.ruby, extconf, *ARGV.grep(/\A--?/) }
42
124
  end
43
125
 
126
+ desc 'Compile the extension for the current Ruby'
127
+ task compile: makefile do
128
+ make = Shellwords.split(ENV['MAKE'] || RbConfig::CONFIG['MAKE'] || 'make')
129
+ Dir.chdir(build_dir) { sh(*make) }
130
+ cp File.join(build_dir, binary), File.join('lib', binary)
131
+ end
132
+ task 'compile:shapelib_ext' => :compile
133
+
134
+ CLEAN.include(build_dir)
135
+ CLOBBER.include('tmp', File.join('lib', binary))
136
+
137
+ rdoc_files = FileList['README*', 'lib/**/*.rb']
138
+ desc 'Build the HTML documentation'
139
+ task rdoc: 'rdoc/created.rid'
140
+ file 'rdoc/created.rid' => rdoc_files.to_a + ['Rakefile'] do
141
+ begin
142
+ require 'rdoc'
143
+ rescue LoadError => error
144
+ raise unless error.path == 'rdoc'
44
145
 
45
- gem 'rake-compiler', '>= 0.7.0'
46
- require "rake/extensiontask"
146
+ abort 'Documentation requires RDoc. Install it with: gem install rdoc'
147
+ end
148
+ RDoc::RDoc.new.document(['--op', 'rdoc', '--title', 'shapelib', *rdoc_files])
149
+ end
47
150
 
48
- Rake::ExtensionTask.new('shapelib_ext')
151
+ desc 'Rebuild the HTML documentation from scratch'
152
+ task rerdoc: %i[clobber_rdoc rdoc]
153
+ desc 'Remove generated HTML documentation'
154
+ task :clobber_rdoc do
155
+ rm_rf 'rdoc'
156
+ end
157
+ task clobber: :clobber_rdoc
data/doc/Interface.html CHANGED
@@ -8,9 +8,9 @@
8
8
  <link href="style.css" type="text/css" rel="stylesheet" />
9
9
  </head>
10
10
  <body>
11
- <h1><a name="label-0" id="label-0">module ShapeLib</a></h1><!-- RDLabel: "module ShapeLib" -->
11
+ <h1><a name="label-0" id="label-0">module Shapelib</a></h1><!-- RDLabel: "module Shapelib" -->
12
12
  <p>This module is a wrapper of C Shapefile Library
13
- (also called <a href="http://shapelib.maptools.org/">ShapeLib</a>).
13
+ (also called <a href="http://shapelib.maptools.org/">Shapelib</a>).
14
14
  It consists of basically two classes:
15
15
  <a href="#label-5">ShapeFile</a> and <a href="#label-29">Shape</a>.
16
16
  If you are unfamiliar with object-oriented programming,
@@ -20,17 +20,17 @@ please see <a href="#label-83">Appendix A: C to Ruby equivalence table</a>.</p>
20
20
  <h2><a name="label-1" id="label-1">module functions</a></h2><!-- RDLabel: "module functions" -->
21
21
  <p>Following three functions construct a point object.
22
22
  It can be used like top level function after <code>include</code>:</p>
23
- <pre>include ShapeLib
23
+ <pre>include Shapelib
24
24
  pt = new_point(1, 2)</pre>
25
25
  <p>Arguments <var>x</var>, <var>y</var>, <var>z</var>, and <var>m</var> <a href="#label-85">should be Float</a>.</p>
26
26
  <dl>
27
- <dt><a name="label-2" id="label-2"><code>ShapeLib.new_point <var>x</var>, <var>y</var></code></a></dt><!-- RDLabel: "ShapeLib.new_point x, y" -->
27
+ <dt><a name="label-2" id="label-2"><code>Shapelib.new_point <var>x</var>, <var>y</var></code></a></dt><!-- RDLabel: "Shapelib.new_point x, y" -->
28
28
  <dd>
29
29
  creates a <a href="#label-51">class Point</a> object.</dd>
30
- <dt><a name="label-3" id="label-3"><code>ShapeLib.new_point <var>x</var>, <var>y</var>, <var>m</var></code></a></dt><!-- RDLabel: "ShapeLib.new_point x, y, m" -->
30
+ <dt><a name="label-3" id="label-3"><code>Shapelib.new_point <var>x</var>, <var>y</var>, <var>m</var></code></a></dt><!-- RDLabel: "Shapelib.new_point x, y, m" -->
31
31
  <dd>
32
32
  creates a <a href="#label-57">class PointM</a> object.</dd>
33
- <dt><a name="label-4" id="label-4"><code>ShapeLib.new_point <var>x</var>, <var>y</var>, <var>m</var>, <var>z</var></code></a></dt><!-- RDLabel: "ShapeLib.new_point x, y, m, z" -->
33
+ <dt><a name="label-4" id="label-4"><code>Shapelib.new_point <var>x</var>, <var>y</var>, <var>m</var>, <var>z</var></code></a></dt><!-- RDLabel: "Shapelib.new_point x, y, m, z" -->
34
34
  <dd>
35
35
  creates a <a href="#label-59">class PointZ</a> object.</dd>
36
36
  </dl>
@@ -52,14 +52,14 @@ or just basename (like "<code>basename</code>").
52
52
  Suffix <code>.shp</code> must be lowercase if specified.
53
53
  Both <code>.shp</code> and <code>.shx</code> files must exist at the specified path.</p>
54
54
  <p>Argument <var>access</var> are passed to <code>fopen(3)</code> through
55
- <a href="#label-92">ShapeLib</a> <code>SHPOpen()</code> function.
55
+ <a href="#label-92">Shapelib</a> <code>SHPOpen()</code> function.
56
56
  Either '<code>rb</code>' or '<code>rb+</code>' should be used.</p>
57
57
  <p>If a block is given to these constructors,
58
58
  the opened shapefile object is yielded like File::open.
59
59
  The shapefile is closed at the end of block,
60
60
  and the constructor returns <code>nil</code>.</p>
61
61
  <pre># example
62
- ShapeLib::ShapeFile.open(filename) { |fp|
62
+ Shapelib::ShapeFile.open(filename) { |fp|
63
63
  print "#{filename} has #{fp.size} records.\n"
64
64
  }</pre></dd>
65
65
  <dt><a name="label-9" id="label-9"><code>ShapeFile::new <var>filename</var>, <var>shapetype</var>, <var>attrs</var></code></a></dt><!-- RDLabel: "ShapeFile::new filename, shapetype, attrs" -->
@@ -90,7 +90,14 @@ Argument <var>field_name</var> is a String for field name;
90
90
  <var>field_type</var> specifies <a href="#label-87">field type</a>;
91
91
  <var>width</var> is nonnegative Integer for field width in characters; and
92
92
  <var>decimal</var> is nonnegative Integer for decimal points.
93
- Only Float field requires <var>decimal</var>; otherwise it can be missing.</p>
93
+ Field names must be at most 10 bytes and unique ignoring case.
94
+ Overlong or duplicate names raise ArgumentError before the field is added.
95
+ Only Float field requires <var>decimal</var>; otherwise it can be missing.
96
+ Integer and Float fields require <var>decimal</var> between 0 and 255 inclusive.
97
+ Date fields require width 8 and zero decimal places. They are available
98
+ when the native shapelib headers provide FTDate (shapelib 1.5.0 or newer).
99
+ Date values are eight-digit YYYYMMDD Strings, or nil for nulls.
100
+ Writes check the eight-digit format without calendar validation.</p>
94
101
  <pre># example
95
102
  fp.add_field 'name', :String, 32
96
103
  fp.add_field 'height', "Float", 9, 1</pre></dd>
@@ -119,8 +126,9 @@ returns the name of the attribute field with <var>index</var>, or nil on failure
119
126
  <dd>
120
127
  returns the type of the <a href="#label-89">attribute field</a>.
121
128
  The result is Symbol
122
- (one of :String, :Integer, :Float, :Logical, or :Invalid)
123
- or nil on failure.</dd>
129
+ (one of :String, :Integer, :Float, :Logical, :Date, or :Invalid)
130
+ or nil on failure.
131
+ Older native libraries classify Date fields as :String.</dd>
124
132
  <dt><a name="label-19" id="label-19"><code>shapefile.field_width <var>field</var></code></a></dt><!-- RDLabel: "shapefile.field_width field" -->
125
133
  <dd>
126
134
  returns the width of the <a href="#label-89">attribute field</a>.</dd>
@@ -142,7 +150,9 @@ the next record to previously read one
142
150
  (or the first record #0 for the first time) is used.
143
151
  An instance of <a href="#label-29">class Shape</a> is returned,
144
152
  including all attributes written on the DBF.
145
- On error <code>nil</code> is returned.</dd>
153
+ At end of file or on a geometry-read failure, <code>nil</code> is returned.
154
+ If a DBF with attribute fields is present but its record cannot be read,
155
+ IOError is raised. Files without a DBF or with no fields remain readable.</dd>
146
156
  <dt><a name="label-24" id="label-24"><code>shapefile.rewind</code></a></dt><!-- RDLabel: "shapefile.rewind" -->
147
157
  <dd>
148
158
  After that, <a href="#label-23">shapefile.read</a>
@@ -159,7 +169,8 @@ returns the number of records (or shapes) in the shapefile.
159
169
  writes <var>shape</var> into shapefile at record number <var>rec</var>.
160
170
  The <var>shape</var> must be a instance of <a href="#label-29">class Shape</a> or subclass.
161
171
  Attributes attached to <var>shape</var> are stored into DBF file.
162
- If <var>rec</var> is missing, the record is appended at the end of shapefile.</dd>
172
+ If <var>rec</var> is missing, nil, or -1, the record is appended at the end of shapefile.
173
+ An existing nonnegative record index replaces that record.</dd>
163
174
  <dt><a name="label-28" id="label-28"><code>shapefile.close</code></a></dt><!-- RDLabel: "shapefile.close" -->
164
175
  <dd>
165
176
  <p>The <code>close</code> method flushes all information
@@ -270,7 +281,7 @@ returns the <a href="#label-86">type of shape</a> by Symbol.</dd>
270
281
  <p>returns a hash that contains all attributes and geometry information.
271
282
  Each attribute have a key of String,
272
283
  while geometry information has keys of Symbol.</p>
273
- <pre>pt = ShapeLib::Point::new(1, 2, 'name' =&gt; 'Madison')
284
+ <pre>pt = Shapelib::Point::new(1, 2, 'name' =&gt; 'Madison')
274
285
  pt.to_h =&gt; {"name"=&gt;"Madison", :zvals=&gt;[0.0], :n_parts=&gt;0,
275
286
  :n_vertices=&gt;1, :maxbound=&gt;[1.0, 2.0, 0.0, 0.0],
276
287
  :part_start=&gt;nil, :part_type=&gt;nil, :xvals=&gt;[1.0],
@@ -285,29 +296,29 @@ Note that this lose information.</dd>
285
296
  <p>returns WKT (well known text) representation of geometry
286
297
  as defined in <a href="#label-94">ISO 19125-1</a>.
287
298
  <em>Caution: current implementation does not always handle Polygon[MZ] and MultiPatch correctly.</em></p>
288
- <pre>ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).wkt
299
+ <pre>Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).wkt
289
300
  =&gt; "LINESTRING(1 2, 3 4, 5 6)"
290
- ShapeLib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).wkt
301
+ Shapelib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).wkt
291
302
  =&gt; "MULTILINESTRING((1 2, 3 4), (5 6, 7 8))"</pre></dd>
292
303
  <dt><a name="label-47" id="label-47"><code>shape.xvals</code></a></dt><!-- RDLabel: "shape.xvals" -->
293
304
  <dd>
294
305
  <p>returns an array of x values.</p>
295
- <pre>ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
306
+ <pre>Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
296
307
  =&gt; [1.0, 3.0, 5.0]</pre>
297
308
  <p>Multipart shape results flattened array (all parts joined).</p>
298
- <pre>ShapeLib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).xvals
309
+ <pre>Shapelib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).xvals
299
310
  =&gt; [1.0, 3.0, 5.0, 7.0]</pre></dd>
300
311
  <dt><a name="label-48" id="label-48"><code>shape.yvals</code></a></dt><!-- RDLabel: "shape.yvals" -->
301
312
  <dd>
302
313
  <p>returns an array of y values.</p>
303
- <pre>ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
314
+ <pre>Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
304
315
  =&gt; [2.0, 4.0, 6.0]</pre></dd>
305
316
  <dt><a name="label-49" id="label-49"><code>shape.mvals</code></a></dt><!-- RDLabel: "shape.mvals" -->
306
317
  <dd>
307
318
  <p>returns an array of m values. Nil is returned for missing value.</p>
308
- <pre>ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).mvals
319
+ <pre>Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).mvals
309
320
  =&gt; [nil, nil, nil]
310
- ShapeLib::ArcM.new([1, 2, 3], [4, 5, 6], [7, 8, 9]).mvals
321
+ Shapelib::ArcM.new([1, 2, 3], [4, 5, 6], [7, 8, 9]).mvals
311
322
  =&gt; [3, 6, 9]</pre></dd>
312
323
  <dt><a name="label-50" id="label-50"><code>shape.zvals</code></a></dt><!-- RDLabel: "shape.zvals" -->
313
324
  <dd>
@@ -382,7 +393,11 @@ Constructs a object with multiple polygons.</dd>
382
393
  <dt><a name="label-72" id="label-72"><code>MultiPoint::new <var>point</var>, <var>point</var>, ...</code></a></dt><!-- RDLabel: "MultiPoint::new point, point, ..." -->
383
394
  <dt><a name="label-73" id="label-73"><code>MultiPoint::new [<var>point</var>, <var>point</var>, ...]</code></a></dt><!-- RDLabel: "MultiPoint::new [point, point, ...]" -->
384
395
  <dd>
385
- Above two are the same.</dd>
396
+ Above two are the same for a nonempty list of points. Each point may
397
+ be a coordinate array [x, y, m, z] or an object with x and y methods.
398
+ A single coordinate array is also accepted. No arguments create an
399
+ empty MultiPoint; for compatibility, a single empty array creates
400
+ one point at the origin.</dd>
386
401
  </dl>
387
402
  <h2><a name="label-74" id="label-74">class MultiPointM</a></h2><!-- RDLabel: "class MultiPointM" -->
388
403
  <p>MultiPointM is similar to MultiPoint, but points also have m (measure) coordinates.</p>
@@ -398,9 +413,11 @@ Note that the first element of each array must be <a href="#label-88">part type<
398
413
  <h2><a name="label-78" id="label-78">constants</a></h2><!-- RDLabel: "constants" -->
399
414
  <h3><a name="label-79" id="label-79">Field Type Constants</a></h3><!-- RDLabel: "Field Type Constants" -->
400
415
  <dl>
401
- <dt><a name="label-80" id="label-80"><code>ShapeLib::String</code></a></dt><!-- RDLabel: "ShapeLib::String" -->
402
- <dt><a name="label-81" id="label-81"><code>ShapeLib::Integer</code></a></dt><!-- RDLabel: "ShapeLib::Integer" -->
403
- <dt><a name="label-82" id="label-82"><code>ShapeLib::Float</code></a></dt><!-- RDLabel: "ShapeLib::Float" -->
416
+ <dt><a name="label-80" id="label-80"><code>Shapelib::String</code></a></dt><!-- RDLabel: "Shapelib::String" -->
417
+ <dt><a name="label-81" id="label-81"><code>Shapelib::Integer</code></a></dt><!-- RDLabel: "Shapelib::Integer" -->
418
+ <dt><a name="label-82" id="label-82"><code>Shapelib::Float</code></a></dt><!-- RDLabel: "Shapelib::Float" -->
419
+ <dt><code>Shapelib::Date</code></dt>
420
+ <dd>Available when the native shapelib headers provide FTDate.</dd>
404
421
  </dl>
405
422
  <h2><a name="label-83" id="label-83">Appendix A: C to Ruby equivalence table</a></h2><!-- RDLabel: "Appendix A: C to Ruby equivalence table" -->
406
423
  <ul>
@@ -478,8 +495,12 @@ This appendix discusses the detail of acceptable value.</p>
478
495
  <dd>
479
496
  Any object that respond to <code>to_f</code> is converted to Float.
480
497
  String is not acceptable.
481
- <code>nil</code> is treated as -2e-38 (NODATA) for <var>m</var> (measure) coordinate,
498
+ <code>nil</code> is treated as -2e38 (NODATA) for <var>m</var> (measure) coordinate,
482
499
  or as 0.0 otherwise.
500
+ Measures below -1e38 are read as nil; exactly -1e38 is valid.
501
+ The exact legacy null marker -2e-38 is also read as nil for compatibility
502
+ with files written by older versions of this gem. Other negative measures
503
+ are preserved.
483
504
  </dd>
484
505
  <dt><a name="label-86" id="label-86">type of shapes</a></dt><!-- RDLabel: "type of shapes" -->
485
506
  <dd>
@@ -487,9 +508,9 @@ For <a href="#label-9">ShapeFile::new</a>
487
508
  and <a href="#label-32">Shape::new</a>,
488
509
  acceptable values for <var>shapetype</var> are:
489
510
  <ul>
490
- <li>Class object like ShapeLib::Point (listed in <a href="#label-30">structure of subclasses</a>)</li>
511
+ <li>Class object like Shapelib::Point (listed in <a href="#label-30">structure of subclasses</a>)</li>
491
512
  <li>String such as <code>"Point"</code> or <code>"PolygonZ"</code>
492
- (the same list, but do not include "ShapeLib::")</li>
513
+ (the same list, but do not include "Shapelib::")</li>
493
514
  <li>Symbol such as <code>:Point</code> or <code>:PolygonZ</code>
494
515
  (result of <a href="#label-25">shapefile.shape_type</a> and <a href="#label-43">shape.shape_type</a>),
495
516
  or</li>
@@ -502,8 +523,8 @@ acceptable values for <var>shapetype</var> are:
502
523
  For <a href="#label-12">shapefile.add_field</a>,
503
524
  acceptable values for <var>field_type</var> are:
504
525
  <ul>
505
- <li>String "String", "Integer", or "Float", or</li>
506
- <li>Symbol :String, :Integer, or :Float
526
+ <li>String "String", "Integer", "Float", "Logical", or "Date", or</li>
527
+ <li>Symbol :String, :Integer, :Float, :Logical, or :Date
507
528
  (result of <a href="#label-18">shapefile.field_type</a>).</li>
508
529
  <li>Integer constants listed <a href="#label-79">above</a>.</li>
509
530
  </ul>
@@ -533,7 +554,7 @@ For <a href="#label-32">Shape::new hash</a>, the argument <var>hash</var>
533
554
  </dl>
534
555
  <h2><a name="label-91" id="label-91">References</a></h2><!-- RDLabel: "References" -->
535
556
  <dl>
536
- <dt><a name="label-92" id="label-92">ShapeLib</a></dt><!-- RDLabel: "ShapeLib" -->
557
+ <dt><a name="label-92" id="label-92">Shapelib</a></dt><!-- RDLabel: "Shapelib" -->
537
558
  <dd>
538
559
  <a href="http://shapelib.maptools.org/shp_api.html">&lt;URL:http://shapelib.maptools.org/shp_api.html&gt;</a>
539
560
  <a href="http://shapelib.maptools.org/dbf_api.html">&lt;URL:http://shapelib.maptools.org/dbf_api.html&gt;</a>
@@ -552,7 +573,7 @@ or <a href="http://shapelib.maptools.org/dl/shapefile.pdf">&lt;URL:http://shapel
552
573
  <p class="foottext">
553
574
  <a name="foottext-1" id="foottext-1" href="#footmark-1"><sup><small>*1</small></sup></a><small>If DBF file has different number of records,
554
575
  warning message is shown in $VERBOSE mode.</small><br />
555
- <a name="foottext-2" id="foottext-2" href="#footmark-2"><sup><small>*2</small></sup></a><small>taken from <a href="#label-92">ShapeLib</a> document.</small><br />
576
+ <a name="foottext-2" id="foottext-2" href="#footmark-2"><sup><small>*2</small></sup></a><small>taken from <a href="#label-92">Shapelib</a> document.</small><br />
556
577
  </p>
557
578
  </body>
558
579
  </html>
data/doc/Interface.rd CHANGED
@@ -1,8 +1,8 @@
1
1
  =begin
2
- = module ShapeLib
2
+ = module Shapelib
3
3
 
4
4
  This module is a wrapper of C Shapefile Library
5
- (also called ((<ShapeLib|URL:http://shapelib.maptools.org/>))).
5
+ (also called ((<Shapelib|URL:http://shapelib.maptools.org/>))).
6
6
  It consists of basically two classes:
7
7
  ((<ShapeFile|class ShapeFile>)) and ((<Shape|class Shape>)).
8
8
  If you are unfamiliar with object-oriented programming,
@@ -16,16 +16,16 @@ A extension library (({shapelib})) must be required before using this module:
16
16
  Following three functions construct a point object.
17
17
  It can be used like top level function after (({include})):
18
18
 
19
- include ShapeLib
19
+ include Shapelib
20
20
  pt = new_point(1, 2)
21
21
 
22
22
  Arguments ((|x|)), ((|y|)), ((|z|)), and ((|m|)) ((<should be Float>)).
23
23
 
24
- --- ShapeLib.new_point x, y
24
+ --- Shapelib.new_point x, y
25
25
  creates a ((<class Point>)) object.
26
- --- ShapeLib.new_point x, y, m
26
+ --- Shapelib.new_point x, y, m
27
27
  creates a ((<class PointM>)) object.
28
- --- ShapeLib.new_point x, y, m, z
28
+ --- Shapelib.new_point x, y, m, z
29
29
  creates a ((<class PointZ>)) object.
30
30
 
31
31
  == class ShapeFile
@@ -47,7 +47,7 @@ when each shapefile is no longer used.
47
47
  Both (({.shp})) and (({.shx})) files must exist at the specified path.
48
48
 
49
49
  Argument ((|access|)) are passed to (({fopen(3)})) through
50
- ((<ShapeLib>)) (({SHPOpen()})) function.
50
+ ((<Shapelib>)) (({SHPOpen()})) function.
51
51
  Either '(({rb}))' or '(({rb+}))' should be used.
52
52
 
53
53
  If a block is given to these constructors,
@@ -56,7 +56,7 @@ when each shapefile is no longer used.
56
56
  and the constructor returns (({nil})).
57
57
 
58
58
  # example
59
- ShapeLib::ShapeFile.open(filename) { |fp|
59
+ Shapelib::ShapeFile.open(filename) { |fp|
60
60
  print "#{filename} has #{fp.size} records.\n"
61
61
  }
62
62
 
@@ -87,7 +87,14 @@ when each shapefile is no longer used.
87
87
  ((|field_type|)) specifies ((<field type>));
88
88
  ((|width|)) is nonnegative Integer for field width in characters; and
89
89
  ((|decimal|)) is nonnegative Integer for decimal points.
90
+ Field names must be at most 10 bytes and unique ignoring case.
91
+ Overlong or duplicate names raise ArgumentError before the field is added.
90
92
  Only Float field requires ((|decimal|)); otherwise it can be missing.
93
+ Integer and Float fields require ((|decimal|)) between 0 and 255 inclusive.
94
+ Date fields require width 8 and zero decimal places. They are available
95
+ when the native shapelib headers provide FTDate (shapelib 1.5.0 or newer).
96
+ Date values are eight-digit YYYYMMDD Strings, or nil for nulls.
97
+ Writes check the eight-digit format without calendar validation.
91
98
 
92
99
  # example
93
100
  fp.add_field 'name', :String, 32
@@ -118,8 +125,9 @@ when each shapefile is no longer used.
118
125
  --- shapefile.field_type field
119
126
  returns the type of the ((<attribute field>)).
120
127
  The result is Symbol
121
- (one of :String, :Integer, :Float, :Logical, or :Invalid)
128
+ (one of :String, :Integer, :Float, :Logical, :Date, or :Invalid)
122
129
  or nil on failure.
130
+ Older native libraries classify Date fields as :String.
123
131
 
124
132
  --- shapefile.field_width field
125
133
  returns the width of the ((<attribute field>)).
@@ -141,7 +149,9 @@ when each shapefile is no longer used.
141
149
  (or the first record #0 for the first time) is used.
142
150
  An instance of ((<class Shape>)) is returned,
143
151
  including all attributes written on the DBF.
144
- On error (({nil})) is returned.
152
+ At end of file or on a geometry-read failure, (({nil})) is returned.
153
+ If a DBF with attribute fields is present but its record cannot be read,
154
+ IOError is raised. Files without a DBF or with no fields remain readable.
145
155
 
146
156
  --- shapefile.rewind
147
157
  After that, ((<shapefile.read|shapefile.read rec = -1>))
@@ -159,7 +169,8 @@ when each shapefile is no longer used.
159
169
  writes ((|shape|)) into shapefile at record number ((|rec|)).
160
170
  The ((|shape|)) must be a instance of ((<class Shape>)) or subclass.
161
171
  Attributes attached to ((|shape|)) are stored into DBF file.
162
- If ((|rec|)) is missing, the record is appended at the end of shapefile.
172
+ If ((|rec|)) is missing, nil, or -1, the record is appended at the end of shapefile.
173
+ An existing nonnegative record index replaces that record.
163
174
 
164
175
  --- shapefile.close
165
176
  The (({close})) method flushes all information
@@ -231,7 +242,7 @@ depending on the type of shape.
231
242
  It returns (({true})) if a change is made and
232
243
  (({false})) if no change is made.
233
244
  Only polygon objects will be affected though any object may be passed."
234
- ((-taken from ((<ShapeLib>)) document.-))
245
+ ((-taken from ((<Shapelib>)) document.-))
235
246
  --- shape.shape_id
236
247
  returns the number of record by which the shape is read from a shapefile.
237
248
  Nil is returned if the shape is not read from file.
@@ -243,7 +254,7 @@ depending on the type of shape.
243
254
  returns a hash that contains all attributes and geometry information.
244
255
  Each attribute have a key of String,
245
256
  while geometry information has keys of Symbol.
246
- pt = ShapeLib::Point::new(1, 2, 'name' => 'Madison')
257
+ pt = Shapelib::Point::new(1, 2, 'name' => 'Madison')
247
258
  pt.to_h => {"name"=>"Madison", :zvals=>[0.0], :n_parts=>0,
248
259
  :n_vertices=>1, :maxbound=>[1.0, 2.0, 0.0, 0.0],
249
260
  :part_start=>nil, :part_type=>nil, :xvals=>[1.0],
@@ -259,34 +270,34 @@ depending on the type of shape.
259
270
  as defined in ((<ISO 19125-1>)).
260
271
  ((*Caution: current implementation does not always handle Polygon[MZ] and MultiPatch correctly.*))
261
272
 
262
- ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).wkt
273
+ Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).wkt
263
274
  => "LINESTRING(1 2, 3 4, 5 6)"
264
- ShapeLib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).wkt
275
+ Shapelib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).wkt
265
276
  => "MULTILINESTRING((1 2, 3 4), (5 6, 7 8))"
266
277
 
267
278
  --- shape.xvals
268
279
  returns an array of x values.
269
280
 
270
- ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
281
+ Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
271
282
  => [1.0, 3.0, 5.0]
272
283
 
273
284
  Multipart shape results flattened array (all parts joined).
274
285
 
275
- ShapeLib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).xvals
286
+ Shapelib::Arc.new([[1, 2], [3, 4]], [[5, 6], [7, 8]]).xvals
276
287
  => [1.0, 3.0, 5.0, 7.0]
277
288
 
278
289
  --- shape.yvals
279
290
  returns an array of y values.
280
291
 
281
- ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
292
+ Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).xvals
282
293
  => [2.0, 4.0, 6.0]
283
294
 
284
295
  --- shape.mvals
285
296
  returns an array of m values. Nil is returned for missing value.
286
297
 
287
- ShapeLib::Arc.new([1, 2], [3, 4], [5, 6]).mvals
298
+ Shapelib::Arc.new([1, 2], [3, 4], [5, 6]).mvals
288
299
  => [nil, nil, nil]
289
- ShapeLib::ArcM.new([1, 2, 3], [4, 5, 6], [7, 8, 9]).mvals
300
+ Shapelib::ArcM.new([1, 2, 3], [4, 5, 6], [7, 8, 9]).mvals
290
301
  => [3, 6, 9]
291
302
 
292
303
  --- shape.zvals
@@ -353,7 +364,11 @@ PolygonZ is similar to PolygonM, but points also have z coordinates.
353
364
  MultiPoint is a set of points.
354
365
  --- MultiPoint::new point, point, ...
355
366
  --- MultiPoint::new [point, point, ...]
356
- Above two are the same.
367
+ Above two are the same for a nonempty list of points. Each point may
368
+ be a coordinate array [x, y, m, z] or an object with x and y methods.
369
+ A single coordinate array is also accepted. No arguments create an
370
+ empty MultiPoint; for compatibility, a single empty array creates
371
+ one point at the origin.
357
372
 
358
373
  == class MultiPointM
359
374
  MultiPointM is similar to MultiPoint, but points also have m (measure) coordinates.
@@ -368,9 +383,11 @@ MultiPointZ is similar to MultiPointM, but points also have z coordinates.
368
383
 
369
384
  == constants
370
385
  === Field Type Constants
371
- --- ShapeLib::String
372
- --- ShapeLib::Integer
373
- --- ShapeLib::Float
386
+ --- Shapelib::String
387
+ --- Shapelib::Integer
388
+ --- Shapelib::Float
389
+ --- Shapelib::Date
390
+ Available when the native shapelib headers provide FTDate.
374
391
 
375
392
  == Appendix A: C to Ruby equivalence table
376
393
  * DBFHandle:
@@ -446,16 +463,20 @@ This appendix discusses the detail of acceptable value.
446
463
  : should be Float
447
464
  Any object that respond to (({to_f})) is converted to Float.
448
465
  String is not acceptable.
449
- (({nil})) is treated as -2e-38 (NODATA) for ((|m|)) (measure) coordinate,
466
+ (({nil})) is treated as -2e38 (NODATA) for ((|m|)) (measure) coordinate,
450
467
  or as 0.0 otherwise.
468
+ Measures below -1e38 are read as nil; exactly -1e38 is valid.
469
+ The exact legacy null marker -2e-38 is also read as nil for compatibility
470
+ with files written by older versions of this gem. Other negative measures
471
+ are preserved.
451
472
 
452
473
  : type of shapes
453
474
  For ((<ShapeFile::new|ShapeFile::new filename, shapetype, attrs>))
454
475
  and ((<Shape::new|Shape::new hash>)),
455
476
  acceptable values for ((|shapetype|)) are:
456
- * Class object like ShapeLib::Point (listed in ((<structure of subclasses>)))
477
+ * Class object like Shapelib::Point (listed in ((<structure of subclasses>)))
457
478
  * String such as (({"Point"})) or (({"PolygonZ"}))
458
- (the same list, but do not include "ShapeLib::")
479
+ (the same list, but do not include "Shapelib::")
459
480
  * Symbol such as (({:Point})) or (({:PolygonZ}))
460
481
  (result of ((<shapefile.shape_type>)) and ((<shape.shape_type>))),
461
482
  or
@@ -465,8 +486,8 @@ This appendix discusses the detail of acceptable value.
465
486
  : field type
466
487
  For ((<shapefile.add_field|shapefile.add_field field_name, field_type, width, decimal = 0>)),
467
488
  acceptable values for ((|field_type|)) are:
468
- * String "String", "Integer", or "Float", or
469
- * Symbol :String, :Integer, or :Float
489
+ * String "String", "Integer", "Float", "Logical", or "Date", or
490
+ * Symbol :String, :Integer, :Float, :Logical, or :Date
470
491
  (result of ((<shapefile.field_type|shapefile.field_type field>))).
471
492
  * Integer constants listed ((<above|Field Type Constants>)).
472
493
 
@@ -487,7 +508,7 @@ This appendix discusses the detail of acceptable value.
487
508
 
488
509
 
489
510
  == References
490
- : ShapeLib
511
+ : Shapelib
491
512
  ((<URL:http://shapelib.maptools.org/shp_api.html>))
492
513
  ((<URL:http://shapelib.maptools.org/dbf_api.html>))
493
514
  : ESRI Whitepaper