underpass 0.9.1 → 0.9.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e5920d16962c26dd7711747653a0ce891250e870d2a675f51402354306a3e93
4
- data.tar.gz: 1770e8e1e320916d9a53673df975ec1a7293d0d1064bdb0d68c2ab50cd168aeb
3
+ metadata.gz: 5537c4b977692f332de7f6b4432f000da4c025005118521df1272d74719a6245
4
+ data.tar.gz: 83455326c173828d22cb7f983612e4c726e13047ef4dea721b304f5d722472b3
5
5
  SHA512:
6
- metadata.gz: f67e73666224ec23cf123b2803438a4b893359039da09fd9209506dea49b2b8685b04a8287955bc2c811224d786a9ca17be7ebcd22fc64242000147d10fe0ae8
7
- data.tar.gz: dcbf032eae5a06497068f36861073dfa846d889c4bbab7681db81127a878824a70edb43dffb022bcae188afb8a40b2bea7deae6d3be9fc4cd429246fdf2e8fc4
6
+ metadata.gz: e91f105de2883607534d05c777c1bf83ae7f160461f33dbbb6a2ab273faf6ef9f93cfdf312c7bf21a161e7355325488c1ca4cb0c99c29251a94eabdbfbe85ab7
7
+ data.tar.gz: 0fca925ecf8188fb6aa16d62162b51c671336d90124c490bff82a9e02e31158d3b92a8f816338f1178f2a8dfdf6e50adfb61888eec15fb6fb31ccef29161b187
data/README.md CHANGED
@@ -420,6 +420,19 @@ rescue Underpass::ApiError => e
420
420
  end
421
421
  ```
422
422
 
423
+ For syntax errors (the most common 400 from Overpass), the structured data is just as rich:
424
+
425
+ ```ruby
426
+ begin
427
+ Underpass::QL::Query.perform_raw('nod["amenity"="cafe"];')
428
+ rescue Underpass::ApiError => e
429
+ e.code # => "syntax"
430
+ e.http_status # => 400
431
+ e.error_message # => "Error: line 3: parse error: Unknown type \"nod\""
432
+ e.details # => { line: 3 }
433
+ end
434
+ ```
435
+
423
436
  ### Error Codes
424
437
 
425
438
  | Code | Description | HTTP Status |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'cgi'
4
+
3
5
  module Underpass
4
6
  # Parses HTML error responses from the Overpass API into structured data.
5
7
  #
@@ -35,26 +37,53 @@ module Underpass
35
37
 
36
38
  # Extracts error text from HTML or returns the body as-is.
37
39
  #
40
+ # Overpass sometimes wraps the real error message in a <p> and uses
41
+ # <strong> only as an inline label (e.g. "<p><strong>Error</strong>:
42
+ # line 3: parse error: ...</p>"). Scan every <p> first and prefer one
43
+ # whose stripped text matches a known pattern, so label-only <strong>
44
+ # tags don't swallow the useful content.
45
+ #
38
46
  # @param body [String] the response body
39
47
  # @return [String] the extracted error text
40
48
  def self.extract_error_text(body)
41
49
  return '' if body.nil? || body.empty?
42
50
 
43
- # Try to extract text from <strong> tags (common Overpass error format)
44
- if (match = body.match(%r{<strong[^>]*>(.*?)</strong>}im))
45
- return match[1].gsub(/<[^>]+>/, '').strip
46
- end
51
+ paragraphs = extract_paragraphs(body)
52
+ from_paragraphs = pick_paragraph(paragraphs)
53
+ return CGI.unescapeHTML(from_paragraphs) if from_paragraphs
47
54
 
48
- # Try to extract from <p> tags
49
- if (match = body.match(%r{<p[^>]*>(.*?)</p>}im))
50
- return match[1].gsub(/<[^>]+>/, '').strip
51
- end
55
+ from_strong = extract_strong_text(body)
56
+ return CGI.unescapeHTML(from_strong) unless from_strong.empty?
52
57
 
53
- # Fall back to stripping all HTML tags
54
- body.gsub(/<[^>]+>/, ' ').gsub(/\s+/, ' ').strip
58
+ CGI.unescapeHTML(body.gsub(/<[^>]+>/, ' ').gsub(/\s+/, ' ').strip)
55
59
  end
56
60
  private_class_method :extract_error_text
57
61
 
62
+ def self.extract_paragraphs(body)
63
+ body.scan(%r{<p[^>]*>(.*?)</p>}im)
64
+ .map { |m| m[0].gsub(/<[^>]+>/, '').strip }
65
+ .reject(&:empty?)
66
+ end
67
+ private_class_method :extract_paragraphs
68
+
69
+ # Picks the first paragraph matching a known pattern, or the last
70
+ # paragraph as a general-context fallback.
71
+ def self.pick_paragraph(paragraphs)
72
+ return if paragraphs.empty?
73
+
74
+ matched = paragraphs.find { |p| PATTERNS.each_value.any? { |rx| p.match?(rx) } }
75
+ matched || paragraphs.last
76
+ end
77
+ private_class_method :pick_paragraph
78
+
79
+ def self.extract_strong_text(body)
80
+ match = body.match(%r{<strong[^>]*>(.*?)</strong>}im)
81
+ return '' unless match
82
+
83
+ match[1].gsub(/<[^>]+>/, '').strip
84
+ end
85
+ private_class_method :extract_strong_text
86
+
58
87
  # Parses the error text against known patterns.
59
88
  #
60
89
  # @param text [String] the extracted error text
@@ -84,9 +113,9 @@ module Underpass
84
113
  private_class_method :parse_memory
85
114
 
86
115
  def self.parse_syntax(text)
87
- return unless (match = text.match(PATTERNS[:syntax]))
116
+ return unless text.match(PATTERNS[:syntax])
88
117
 
89
- { code: 'syntax', message: match[1].strip, details: extract_syntax_details(match[1]) }
118
+ { code: 'syntax', message: text.strip, details: extract_syntax_details(text) }
90
119
  end
91
120
  private_class_method :parse_syntax
92
121
 
@@ -20,8 +20,11 @@ module Underpass
20
20
  #
21
21
  # @param way [Hash] a parsed way element
22
22
  # @param nodes [Hash{Integer => Hash}] node lookup table
23
- # @return [RGeo::Feature::Polygon] the polygon geometry
23
+ # @return [RGeo::Feature::Polygon, nil] the polygon geometry, or +nil+
24
+ # if the way has fewer than 4 points
24
25
  def polygon_from_way(way, nodes)
26
+ return nil if way[:nodes].size < 4
27
+
25
28
  factory.polygon(line_string_from_way(way, nodes))
26
29
  end
27
30
 
@@ -103,7 +106,11 @@ module Underpass
103
106
  return [] if way_ids.empty?
104
107
 
105
108
  sequences = WayChain.new(way_ids, ways).merged_sequences
106
- sequences.map { |ids| factory.linear_ring(points_from_node_ids(ids, nodes)) }
109
+ sequences.filter_map do |ids|
110
+ next if ids.size < 4
111
+
112
+ factory.linear_ring(points_from_node_ids(ids, nodes))
113
+ end
107
114
  end
108
115
 
109
116
  def matching_inner_rings(outer_ring, inner_rings)
@@ -13,7 +13,7 @@ module Underpass
13
13
  module VERSION
14
14
  MAJOR = 0
15
15
  MINOR = 9
16
- PATCH = 1
16
+ PATCH = 2
17
17
 
18
18
  STRING = [MAJOR, MINOR, PATCH].join('.')
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: underpass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janos Rusiczki