epok 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/README.md +4 -4
- data/lib/epok/api.rb +14 -2
- data/lib/epok/object.rb +7 -5
- data/lib/epok/version.rb +1 -1
- data/lib/epok.rb +9 -6
- metadata +12 -25
- data/.claude/skills/swarf/SKILL.md +0 -77
- data/.gitignore +0 -10
- data/CLAUDE.md +0 -47
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -90
- data/Rakefile +0 -10
- data/bin/console +0 -7
- data/bin/setup +0 -7
- data/epok.gemspec +0 -24
- data/test/epok/api_test.rb +0 -65
- data/test/epok/categories_test.rb +0 -26
- data/test/epok/collection_test.rb +0 -22
- data/test/epok/datos_utiles_test.rb +0 -39
- data/test/epok/geocode_test.rb +0 -36
- data/test/epok/geocoder_test.rb +0 -49
- data/test/epok/object_test.rb +0 -82
- data/test/epok/search_test.rb +0 -47
- data/test/epok_test.rb +0 -13
- data/test/test_helper.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74780db81aad8442533598aab22a695b4565710ce30ab5504439f59e55587195
|
|
4
|
+
data.tar.gz: d3562a616e0f3d28a666041f43abaa770e0bdbf386b581f64f5d225ccc6cbbd4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02e22d2fb37d7b44611461af1bcc7e006b6a97d78c54a07416f092e9a00a989b26bd6a0bc38a6558378a200fb177e7c921a54f970e388711fa520888ab71f16e
|
|
7
|
+
data.tar.gz: 637d65db4058187386da2b632685b1488749eb859689bfaf242d962803d05fbfd1147f78d41256ea005445307e3ec8e5258c7b4c9437c2187181ddd5e9b4dfc7
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
|
|
5
|
+
follows [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.6.0] - 2026-09-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Breaking:** `Epok.geocoder` is now `Epok.nearby`. Next to `Epok.geocode`
|
|
14
|
+
(address to point) the old name read as the same thing backwards.
|
|
15
|
+
- Every string in an API response is stripped and squeezed once in `API.get`.
|
|
16
|
+
The API pads and double-spaces names at random, in every endpoint, and the
|
|
17
|
+
per-field strips it replaces only covered some of them.
|
|
18
|
+
- Gemspec declares `required_ruby_version >= 3.3`, links the changelog and
|
|
19
|
+
source on rubygems.org, and ships only `lib/`, README, CHANGELOG and
|
|
20
|
+
LICENSE instead of the whole repository (tests and cassettes included).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Malformed responses no longer escape as `NoMethodError`: an unparseable
|
|
25
|
+
centroid raises `Epok::Error`, non-string content values are kept as
|
|
26
|
+
strings, and a geocode match without coordinates has a nil `location`.
|
|
27
|
+
|
|
28
|
+
## [0.5.0] - 2026-09-15
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- `Epok.geocode(text)` turns "cabildo 1234" or "callao y corrientes" into
|
|
33
|
+
`Address` structs with the normalized text, partido, localidad and a
|
|
34
|
+
`Location`, via USIG's normalizer. Unknown addresses raise `Epok::NotFound`
|
|
35
|
+
with the service's message.
|
|
36
|
+
- `Epok.datos_utiles(location)` returns the barrio, comuna, comisaría,
|
|
37
|
+
hospital area, health region and school district for a point. Outside the
|
|
38
|
+
city those are nil and `partido_amba` and `localidad_amba` are filled.
|
|
39
|
+
- `Epok.search` accepts `categories:` (one or an array) and `limit:`.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- README rewritten around an end-to-end example.
|
|
44
|
+
- Removed minitest-reporters from the development dependencies.
|
|
45
|
+
|
|
46
|
+
## [0.4.0] - 2026-09-15
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- `Epok::Object` keeps listing data: `name`, `kind`, `category` and
|
|
51
|
+
`distance` (metres, from the geocoder) are available without a request.
|
|
52
|
+
`content`, `normalized_address` and `location` fetch lazily.
|
|
53
|
+
- `Epok::Object#location` returns longitude and latitude, converted from the
|
|
54
|
+
city's projected grid through USIG. Nil when the object has no centroid.
|
|
55
|
+
- `Epok.categories` lists all EPOk categories as `Category` structs.
|
|
56
|
+
- `Epok.geocoder` accepts `radius:` (default 500 metres) and an array of
|
|
57
|
+
categories.
|
|
58
|
+
- `Epok::Error` wraps timeouts, network failures, non-2xx responses and bad
|
|
59
|
+
JSON. `Epok::NotFound` for unknown ids.
|
|
60
|
+
|
|
61
|
+
## [0.3.0] - 2026-09-15
|
|
62
|
+
|
|
63
|
+
Tagged but never pushed to rubygems.org.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- **Breaking:** `Epok.search` and `Epok.geocoder` return an
|
|
68
|
+
`Epok::Collection`, which is `Enumerable` and lazy. `Epok::Search`,
|
|
69
|
+
`Epok::Geocoder` and `Epok::Collectable` are removed, along with the
|
|
70
|
+
`query`, `x`, `y` and `categories` readers.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- Query parameters are URL-encoded, so non-ASCII searches like "peña" no
|
|
75
|
+
longer raise `URI::InvalidURIError`.
|
|
76
|
+
|
|
77
|
+
## [0.2.0] - 2026-09-15
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- Requests go over HTTPS. The API started redirecting plain HTTP to HTTPS
|
|
82
|
+
with an empty body, which made every call fail with a JSON parse error.
|
|
83
|
+
- Object content values are stripped of surrounding whitespace.
|
|
84
|
+
- Test suite runs on Ruby 4: vcr bumped to 6.x, lockfile regenerated,
|
|
85
|
+
bundler dev dependency dropped.
|
|
86
|
+
|
|
87
|
+
## [0.1.1] - 2019-04-24
|
|
88
|
+
|
|
89
|
+
Initial release: `Epok.search`, `Epok.geocoder` and `Epok::Object`.
|
|
90
|
+
|
|
91
|
+
[Unreleased]: https://github.com/arzezak/epok/compare/v0.6.0...HEAD
|
|
92
|
+
[0.6.0]: https://github.com/arzezak/epok/compare/v0.5.0...v0.6.0
|
|
93
|
+
[0.5.0]: https://github.com/arzezak/epok/compare/v0.4.0...v0.5.0
|
|
94
|
+
[0.4.0]: https://github.com/arzezak/epok/compare/v0.3.0...v0.4.0
|
|
95
|
+
[0.3.0]: https://github.com/arzezak/epok/compare/v0.2.0...v0.3.0
|
|
96
|
+
[0.2.0]: https://github.com/arzezak/epok/compare/e629f99...v0.2.0
|
|
97
|
+
[0.1.1]: https://github.com/arzezak/epok/commits/e629f99
|
data/README.md
CHANGED
|
@@ -34,7 +34,7 @@ area = Epok.datos_utiles(here.location)
|
|
|
34
34
|
puts "That's #{area.barrio}, #{area.comuna}"
|
|
35
35
|
|
|
36
36
|
# 3. What's within 300 metres, by category?
|
|
37
|
-
nearby = Epok.
|
|
37
|
+
nearby = Epok.nearby(here.location, %w[estaciones_de_subte farmacias], radius: 300)
|
|
38
38
|
nearby.sort_by(&:distance).first(5).each do |place|
|
|
39
39
|
puts " #{place.distance.round} m #{place.name} (#{place.kind})"
|
|
40
40
|
end
|
|
@@ -72,16 +72,16 @@ Epok.search("cgp", categories: "sedes_de_comunas", limit: 3).map(&:name)
|
|
|
72
72
|
# => ["Sede Comunal 4", "Sede Comunal 9", "Sede Comunal 10"]
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
**Categories** are what
|
|
75
|
+
**Categories** are what `nearby` and the search filter take. There are 167, each with an id, a display name and a description:
|
|
76
76
|
|
|
77
77
|
```ruby
|
|
78
78
|
Epok.categories.find { |c| c.id == "farmacias" }
|
|
79
79
|
# => #<struct Epok::Category id="farmacias", name="Farmacias", description="">
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
**Collections** from `search` and `
|
|
82
|
+
**Collections** from `search` and `nearby` are `Enumerable` and lazy: nothing is requested until you iterate.
|
|
83
83
|
|
|
84
|
-
**Objects** know their `id`, `name`, `kind`, `category` and, from
|
|
84
|
+
**Objects** know their `id`, `name`, `kind`, `category` and, from `nearby`, `distance` in metres straight from the listing. `content`, `normalized_address` and `location` fetch the full record on first use; `location` also converts the city's projected coordinates through USIG. `Epok::Object.new("farmacias|1082")` looks one up by id.
|
|
85
85
|
|
|
86
86
|
**Locations** are `Epok::Location.new(x: longitude, y: latitude)`. `geocode` returns every match across the metro area, city first, as `Address` structs with `address`, `partido`, `localidad` and `location`. `datos_utiles` returns nil for the city fields outside CABA and fills `partido_amba` and `localidad_amba` instead.
|
|
87
87
|
|
data/lib/epok/api.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Epok
|
|
|
24
24
|
get(EPOK_URL, "/buscar/", params)["instancias"]
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def self.
|
|
27
|
+
def self.nearby(x, y, categories, radius)
|
|
28
28
|
get(EPOK_URL, "/reverseGeocoderLugares/",
|
|
29
29
|
x: x, y: y, categorias: categories, radio: radius)["instancias"]
|
|
30
30
|
end
|
|
@@ -67,10 +67,22 @@ module Epok
|
|
|
67
67
|
raise Error, "EPOk responded #{response.code} to #{uri}"
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
JSON.parse(response.body)
|
|
70
|
+
normalize(JSON.parse(response.body))
|
|
71
71
|
rescue SystemCallError, SocketError, Timeout::Error, OpenSSL::SSL::SSLError, JSON::ParserError => e
|
|
72
72
|
raise Error, "#{e.class}: #{e.message}"
|
|
73
73
|
end
|
|
74
74
|
private_class_method :get
|
|
75
|
+
|
|
76
|
+
# The API pads and double-spaces strings at random. Clean every string
|
|
77
|
+
# in a response once, here, so no field needs its own strip.
|
|
78
|
+
def self.normalize(value)
|
|
79
|
+
case value
|
|
80
|
+
when Hash then value.transform_values { |v| normalize(v) }
|
|
81
|
+
when Array then value.map { |v| normalize(v) }
|
|
82
|
+
when String then value.strip.squeeze(" ")
|
|
83
|
+
else value
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
private_class_method :normalize
|
|
75
87
|
end
|
|
76
88
|
end
|
data/lib/epok/object.rb
CHANGED
|
@@ -3,13 +3,13 @@ module Epok
|
|
|
3
3
|
attr_reader :id, :distance
|
|
4
4
|
|
|
5
5
|
# Accepts either an id ("farmacias|1082") or a result hash from a search
|
|
6
|
-
# or
|
|
6
|
+
# or nearby listing. Listing attributes are available immediately; the
|
|
7
7
|
# full content is fetched on first use.
|
|
8
8
|
def initialize(attributes)
|
|
9
9
|
attributes = { "id" => attributes } if attributes.is_a?(String)
|
|
10
10
|
|
|
11
11
|
@id = attributes.fetch("id")
|
|
12
|
-
@name = attributes["nombre"]
|
|
12
|
+
@name = attributes["nombre"]
|
|
13
13
|
@kind = attributes["clase"]
|
|
14
14
|
@distance = attributes["distancia"]&.to_f
|
|
15
15
|
end
|
|
@@ -37,8 +37,10 @@ module Epok
|
|
|
37
37
|
|
|
38
38
|
centroid = object.dig("ubicacion", "centroide")
|
|
39
39
|
@location = centroid && begin
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
point = centroid[/\(([^)]*)\)/, 1]
|
|
41
|
+
raise Error, "unparseable centroid #{centroid.inspect} for #{id}" unless point
|
|
42
|
+
|
|
43
|
+
lon, lat = API.to_lonlat(*point.split.map(&:to_f))
|
|
42
44
|
Location.new(x: lon, y: lat)
|
|
43
45
|
end
|
|
44
46
|
end
|
|
@@ -46,7 +48,7 @@ module Epok
|
|
|
46
48
|
def content
|
|
47
49
|
object["contenido"].each_with_object({}) do |entry, hash|
|
|
48
50
|
name, value = entry.values_at("nombre", "valor")
|
|
49
|
-
value = value.
|
|
51
|
+
value = value.to_s
|
|
50
52
|
hash[name] = value unless value.empty?
|
|
51
53
|
end
|
|
52
54
|
end
|
data/lib/epok/version.rb
CHANGED
data/lib/epok.rb
CHANGED
|
@@ -23,21 +23,24 @@ module Epok
|
|
|
23
23
|
Collection.new { API.search(query, categories, limit) }
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def self.
|
|
26
|
+
def self.nearby(location, categories, radius: DEFAULT_RADIUS)
|
|
27
27
|
categories = Array(categories).join(",")
|
|
28
28
|
|
|
29
|
-
Collection.new { API.
|
|
29
|
+
Collection.new { API.nearby(location.x, location.y, categories, radius) }
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def self.geocode(text)
|
|
33
33
|
API.geocode(text).map do |address|
|
|
34
|
-
|
|
34
|
+
coordinates = address["coordenadas"]
|
|
35
|
+
location = coordinates && Location.new(
|
|
36
|
+
x: coordinates["x"].to_f, y: coordinates["y"].to_f
|
|
37
|
+
)
|
|
35
38
|
|
|
36
39
|
Address.new(
|
|
37
40
|
address: address["direccion"],
|
|
38
41
|
partido: address["nombre_partido"],
|
|
39
42
|
localidad: address["nombre_localidad"],
|
|
40
|
-
location:
|
|
43
|
+
location: location
|
|
41
44
|
)
|
|
42
45
|
end
|
|
43
46
|
end
|
|
@@ -47,8 +50,8 @@ module Epok
|
|
|
47
50
|
|
|
48
51
|
DatosUtiles.new(
|
|
49
52
|
DatosUtiles.members.to_h do |member|
|
|
50
|
-
value = datos[member.to_s]
|
|
51
|
-
[member, value.empty? ? nil : value]
|
|
53
|
+
value = datos[member.to_s]
|
|
54
|
+
[member, value.to_s.empty? ? nil : value]
|
|
52
55
|
end
|
|
53
56
|
)
|
|
54
57
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: epok
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ariel Rzezak
|
|
@@ -71,44 +71,31 @@ dependencies:
|
|
|
71
71
|
- - ">="
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
73
|
version: 3.5.1
|
|
74
|
-
description:
|
|
74
|
+
description: Search the city's indexed geographic objects, find what is near a point,
|
|
75
|
+
geocode addresses and look up the barrio and comuna of a location, through the GCBA
|
|
76
|
+
EPOk and USIG services.
|
|
75
77
|
email:
|
|
76
78
|
- arzezak@gmail.com
|
|
77
79
|
executables: []
|
|
78
80
|
extensions: []
|
|
79
81
|
extra_rdoc_files: []
|
|
80
82
|
files:
|
|
81
|
-
-
|
|
82
|
-
- ".gitignore"
|
|
83
|
-
- CLAUDE.md
|
|
84
|
-
- CODE_OF_CONDUCT.md
|
|
85
|
-
- Gemfile
|
|
86
|
-
- Gemfile.lock
|
|
83
|
+
- CHANGELOG.md
|
|
87
84
|
- LICENSE.txt
|
|
88
85
|
- README.md
|
|
89
|
-
- Rakefile
|
|
90
|
-
- bin/console
|
|
91
|
-
- bin/setup
|
|
92
|
-
- epok.gemspec
|
|
93
86
|
- lib/epok.rb
|
|
94
87
|
- lib/epok/api.rb
|
|
95
88
|
- lib/epok/collection.rb
|
|
96
89
|
- lib/epok/object.rb
|
|
97
90
|
- lib/epok/version.rb
|
|
98
|
-
- test/epok/api_test.rb
|
|
99
|
-
- test/epok/categories_test.rb
|
|
100
|
-
- test/epok/collection_test.rb
|
|
101
|
-
- test/epok/datos_utiles_test.rb
|
|
102
|
-
- test/epok/geocode_test.rb
|
|
103
|
-
- test/epok/geocoder_test.rb
|
|
104
|
-
- test/epok/object_test.rb
|
|
105
|
-
- test/epok/search_test.rb
|
|
106
|
-
- test/epok_test.rb
|
|
107
|
-
- test/test_helper.rb
|
|
108
91
|
homepage: https://github.com/arzezak/epok
|
|
109
92
|
licenses:
|
|
110
93
|
- MIT
|
|
111
|
-
metadata:
|
|
94
|
+
metadata:
|
|
95
|
+
source_code_uri: https://github.com/arzezak/epok
|
|
96
|
+
changelog_uri: https://github.com/arzezak/epok/blob/main/CHANGELOG.md
|
|
97
|
+
bug_tracker_uri: https://github.com/arzezak/epok/issues
|
|
98
|
+
rubygems_mfa_required: 'true'
|
|
112
99
|
rdoc_options: []
|
|
113
100
|
require_paths:
|
|
114
101
|
- lib
|
|
@@ -116,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
116
103
|
requirements:
|
|
117
104
|
- - ">="
|
|
118
105
|
- !ruby/object:Gem::Version
|
|
119
|
-
version: '
|
|
106
|
+
version: '3.3'
|
|
120
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
108
|
requirements:
|
|
122
109
|
- - ">="
|
|
@@ -125,5 +112,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
125
112
|
requirements: []
|
|
126
113
|
rubygems_version: 4.0.20
|
|
127
114
|
specification_version: 4
|
|
128
|
-
summary:
|
|
115
|
+
summary: Ruby client for the Buenos Aires city EPOk geographic API.
|
|
129
116
|
test_files: []
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: swarf
|
|
3
|
-
description: Score Ruby methods by complexity against test coverage with swarf, and turn the worst rows into the next test to write. Use after writing or changing Ruby code and before calling a change done.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# swarf
|
|
7
|
-
|
|
8
|
-
swarf scores every Ruby method with `CRAP = CC² · (1 − coverage)³ + CC` and lists them worst first. Complexity is parsed from source. Coverage is recorded by a probe loaded into the test run and stored in `.swarf/coverage.json`, so scoring works without setup but coverage needs a test run.
|
|
9
|
-
|
|
10
|
-
## The loop
|
|
11
|
-
|
|
12
|
-
1. Run the suite with the probe loaded (see Setup if unsure):
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
bundle exec rspec # or: bundle exec rake test
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
2. Score the files you touched, not the whole project:
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
git diff --name-only --diff-filter=d main -- '*.rb' | xargs bundle exec swarf
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Named paths are always scored, even under `test/`, `db/` or a `.swarfignore` pattern.
|
|
25
|
-
|
|
26
|
-
3. Take the top rows and act on the Evidence column (next section). Write or extend the test, re-run the suite, score again.
|
|
27
|
-
|
|
28
|
-
4. Stop when the touched methods sit at `CRAP = CC` with `Cov% 100.0`. Nothing you test pulls a score under its CC. If a score is too high at full coverage, that is complexity, which is a refactor question, not a testing one. Do not split methods to chase the number.
|
|
29
|
-
|
|
30
|
-
Before saying a change is done, run step 2 and report the top rows.
|
|
31
|
-
|
|
32
|
-
## Reading a row
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
Method CC Cov% CRAP Evidence Location
|
|
36
|
-
Cart#checkout 6 0.0% 42.00 never called lib/cart.rb:31
|
|
37
|
-
Cart#discount 4 50.0% 6.00 3/6 br lib/cart.rb:24
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
| Evidence | Meaning | Do |
|
|
41
|
-
| -------------- | -------------------------------------------- | ------------------------------------------------------------- |
|
|
42
|
-
| `never called` | A VM call count of zero. No test reaches it. | Write a test that calls it. |
|
|
43
|
-
| `3/6 br` | 3 of 6 branch outcomes ran. | Extend a test to the untaken outcomes. |
|
|
44
|
-
| `1/1 ln` | No branches, so lines are the whole truth. | Nothing, at 100%. |
|
|
45
|
-
| `no data` | No run has been recorded for this file. | The probe is not loaded, or the suite has not run. Fix Setup. |
|
|
46
|
-
| `stale` | The file changed after it was measured. | Re-run the suite, then score again. |
|
|
47
|
-
|
|
48
|
-
`no data` and `stale` both score at the `CC² + CC` floor rather than guess. They are also counted per file under the table, because the fix is per file.
|
|
49
|
-
|
|
50
|
-
A `never called` on a method a test clearly exercises means the test ran without the probe, or the probe loaded after the file. Check Setup before writing a duplicate test.
|
|
51
|
-
|
|
52
|
-
## Setup
|
|
53
|
-
|
|
54
|
-
The probe must load before the code under test, because `Coverage` only sees files loaded after it starts. One line, placed first:
|
|
55
|
-
|
|
56
|
-
- **RSpec**: first line of `.rspec`: `--require swarf/probe`
|
|
57
|
-
- **Minitest**: first line of `test/test_helper.rb`: `require "swarf/probe"`
|
|
58
|
-
- **Rails**: in `test/test_helper.rb`, after `require "bundler/setup"` and before `require_relative "../config/environment"`. Below the environment require, the whole app is invisible to it.
|
|
59
|
-
- **Anything**: `RUBYOPT="-rswarf/probe" bundle exec rake test`
|
|
60
|
-
|
|
61
|
-
Add `.swarf/` to `.gitignore`. Runs merge, so a single spec file adds to what earlier runs proved; nothing is erased until the file's bytes change.
|
|
62
|
-
|
|
63
|
-
Do not run swarf's probe alongside SimpleCov. Ruby allows one `Coverage.start` per process; if SimpleCov started first, swarf warns and records nothing.
|
|
64
|
-
|
|
65
|
-
## Commands
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
bundle exec swarf # whole project, worst 20
|
|
69
|
-
bundle exec swarf lib/ app/ # directories
|
|
70
|
-
bundle exec swarf app/models/cart.rb # one file
|
|
71
|
-
bundle exec swarf --limit 0 # every row
|
|
72
|
-
bundle exec swarf --ignore "app/legacy/**"
|
|
73
|
-
bundle exec swarf --all # ignore nothing, including db/ and .swarfignore
|
|
74
|
-
SWARF_DIR=/tmp/swarf bundle exec swarf # store elsewhere; set for the test run too
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
swarf's CC counts `if`, `unless`, `while`, `until`, `for`, `when`, `in`, `rescue`, `&&`, `||` and `&.`, not blocks, so it will not match RuboCop's. Methods made by `define_method` are not seen.
|
data/.gitignore
DELETED
data/CLAUDE.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Epok
|
|
2
|
-
|
|
3
|
-
Ruby gem wrapping the GCBA EPOk API (https://epok.buenosaires.gob.ar).
|
|
4
|
-
No runtime dependencies beyond the standard library.
|
|
5
|
-
|
|
6
|
-
## Development
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
bundle install
|
|
10
|
-
bundle exec rake test # records VCR cassettes into test/fixtures on first run
|
|
11
|
-
bundle exec swarf lib/ # complexity vs. coverage report, worst first
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Cassettes are gitignored, so the first test run hits the live API.
|
|
15
|
-
The API rejects curl's default User-Agent, but Ruby's Net::HTTP works fine.
|
|
16
|
-
|
|
17
|
-
## API notes
|
|
18
|
-
|
|
19
|
-
Official docs are Swagger specs on the city's 3scale portal. The HTML at
|
|
20
|
-
https://datosabiertos-apis.buenosaires.gob.ar/BA_Root/Documentacion is
|
|
21
|
-
JavaScript-rendered; fetch the JSON directly:
|
|
22
|
-
|
|
23
|
-
- Index: https://datosabiertos-apis.buenosaires.gob.ar/api_docs/services.json
|
|
24
|
-
- EPOk ("Busquedas de Lugares"): .../api_docs/services/10.json
|
|
25
|
-
- USIG Geocoder: .../api_docs/services/8.json
|
|
26
|
-
- Datos Útiles: .../api_docs/services/9.json
|
|
27
|
-
|
|
28
|
-
The specs list `datosabiertos-*-apis.buenosaires.gob.ar` hosts that return
|
|
29
|
-
404. The live hosts are `epok.buenosaires.gob.ar` for EPOk and
|
|
30
|
-
`ws.usig.buenosaires.gob.ar` for USIG (REST index with docs at
|
|
31
|
-
https://ws.usig.buenosaires.gob.ar/rest/).
|
|
32
|
-
|
|
33
|
-
- `/buscar/` also takes `categoria` (comma-separated), `clase`, `bbox`,
|
|
34
|
-
`start`, `limit` and `totalFull`.
|
|
35
|
-
- `/reverseGeocoderLugares/` takes `srid` (default 4326) and `radio`
|
|
36
|
-
(default 1 metre, hence our 500 default).
|
|
37
|
-
- Unknown ids return `200 {}`, unknown categories return an empty list.
|
|
38
|
-
- Object coordinates are projected (Gauss-Krüger Buenos Aires). USIG's
|
|
39
|
-
`/rest/convertir_coordenadas` turns them into longitude and latitude.
|
|
40
|
-
- `ws.usig.buenosaires.gob.ar/datos_utiles?x=&y=` answers with empty strings
|
|
41
|
-
outside the city; `Epok.datos_utiles` turns those into nil.
|
|
42
|
-
- `servicios.usig.buenosaires.gob.ar/normalizar/?direccion=&geocodificar=true`
|
|
43
|
-
matches across the whole AMBA, CABA first. Coordinates come back as
|
|
44
|
-
strings for CABA and floats elsewhere. No match is `200` with an empty
|
|
45
|
-
list and an `errorMessage`; `Epok.geocode` raises NotFound with it.
|
|
46
|
-
- A December 2025 city report says "API USIG" is being replaced by
|
|
47
|
-
"API Servicios Geo" during 2026. The USIG hosts above may move.
|
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
-
orientation.
|
|
11
|
-
|
|
12
|
-
## Our Standards
|
|
13
|
-
|
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
|
15
|
-
include:
|
|
16
|
-
|
|
17
|
-
* Using welcoming and inclusive language
|
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
|
19
|
-
* Gracefully accepting constructive criticism
|
|
20
|
-
* Focusing on what is best for the community
|
|
21
|
-
* Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior by participants include:
|
|
24
|
-
|
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
-
advances
|
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
-
* Public or private harassment
|
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
|
30
|
-
address, without explicit permission
|
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
-
professional setting
|
|
33
|
-
|
|
34
|
-
## Our Responsibilities
|
|
35
|
-
|
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
-
response to any instances of unacceptable behavior.
|
|
39
|
-
|
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
-
threatening, offensive, or harmful.
|
|
45
|
-
|
|
46
|
-
## Scope
|
|
47
|
-
|
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
-
when an individual is representing the project or its community. Examples of
|
|
50
|
-
representing a project or community include using an official project e-mail
|
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
|
53
|
-
further defined and clarified by project maintainers.
|
|
54
|
-
|
|
55
|
-
## Enforcement
|
|
56
|
-
|
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
-
reported by contacting the project team at arzezak@gmail.com. All
|
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
|
63
|
-
|
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
-
members of the project's leadership.
|
|
67
|
-
|
|
68
|
-
## Attribution
|
|
69
|
-
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
-
available at [http://contributor-covenant.org/version/1/4][version]
|
|
72
|
-
|
|
73
|
-
[homepage]: http://contributor-covenant.org
|
|
74
|
-
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
epok (0.5.0)
|
|
5
|
-
|
|
6
|
-
GEM
|
|
7
|
-
remote: https://rubygems.org/
|
|
8
|
-
specs:
|
|
9
|
-
addressable (2.9.0)
|
|
10
|
-
public_suffix (>= 2.0.2, < 8.0)
|
|
11
|
-
bigdecimal (4.1.3)
|
|
12
|
-
crack (1.0.1)
|
|
13
|
-
bigdecimal
|
|
14
|
-
rexml
|
|
15
|
-
erb (6.0.7)
|
|
16
|
-
hashdiff (1.2.1)
|
|
17
|
-
io-console (0.9.3)
|
|
18
|
-
irb (1.18.0)
|
|
19
|
-
pp (>= 0.6.0)
|
|
20
|
-
prism (>= 1.3.0)
|
|
21
|
-
rdoc (>= 4.0.0)
|
|
22
|
-
reline (>= 0.4.2)
|
|
23
|
-
logger (1.7.0)
|
|
24
|
-
minitest (5.27.0)
|
|
25
|
-
pp (0.6.4)
|
|
26
|
-
prettyprint
|
|
27
|
-
prettyprint (0.2.0)
|
|
28
|
-
prism (1.9.0)
|
|
29
|
-
public_suffix (7.0.5)
|
|
30
|
-
rake (13.4.2)
|
|
31
|
-
rbs (4.2.0)
|
|
32
|
-
logger
|
|
33
|
-
prism (>= 1.6.0)
|
|
34
|
-
tsort
|
|
35
|
-
rdoc (8.0.0)
|
|
36
|
-
erb
|
|
37
|
-
prism (>= 1.6.0)
|
|
38
|
-
rbs (>= 4.0.0)
|
|
39
|
-
tsort
|
|
40
|
-
reline (0.7.0)
|
|
41
|
-
io-console (~> 0.5)
|
|
42
|
-
rexml (3.4.4)
|
|
43
|
-
swarf (0.2.0)
|
|
44
|
-
tsort (0.2.0)
|
|
45
|
-
vcr (6.4.0)
|
|
46
|
-
webmock (3.26.4)
|
|
47
|
-
addressable (>= 2.8.0)
|
|
48
|
-
crack (>= 0.3.2)
|
|
49
|
-
hashdiff (>= 0.4.0, < 2.0.0)
|
|
50
|
-
|
|
51
|
-
PLATFORMS
|
|
52
|
-
arm64-darwin-23
|
|
53
|
-
ruby
|
|
54
|
-
|
|
55
|
-
DEPENDENCIES
|
|
56
|
-
epok!
|
|
57
|
-
irb
|
|
58
|
-
minitest (~> 5.0)
|
|
59
|
-
rake (~> 13.0)
|
|
60
|
-
swarf
|
|
61
|
-
vcr (~> 6.0)
|
|
62
|
-
webmock (~> 3.5, >= 3.5.1)
|
|
63
|
-
|
|
64
|
-
CHECKSUMS
|
|
65
|
-
addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
|
|
66
|
-
bigdecimal (4.1.3) sha256=61ebe1e5e559bdc3cc6f2c0ee7f427321fc838f59611c294356eb04d6e21cf66
|
|
67
|
-
crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
|
|
68
|
-
epok (0.5.0)
|
|
69
|
-
erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92
|
|
70
|
-
hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
|
|
71
|
-
io-console (0.9.3) sha256=f555049461b0afb78a5448b5be8e7c7b48371347cd48abfc22814764160000dd
|
|
72
|
-
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
73
|
-
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
74
|
-
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
75
|
-
pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570
|
|
76
|
-
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
77
|
-
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
78
|
-
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
|
|
79
|
-
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
80
|
-
rbs (4.2.0) sha256=51f7b886dcc05bc09e10b901daa6a81829f6adc03101d6ca9ea4aac6103e0674
|
|
81
|
-
rdoc (8.0.0) sha256=03bf8c08a9639658855a0cfd77c0abca8325c227693f7f33f82957811348c469
|
|
82
|
-
reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d
|
|
83
|
-
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
|
84
|
-
swarf (0.2.0) sha256=b4306a244fe4b096cfe263e452e666156856eac2467ae5d770639ef11388b375
|
|
85
|
-
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
|
|
86
|
-
vcr (6.4.0) sha256=077ac92cc16efc5904eb90492a18153b5e6ca5398046d8a249a7c96a9ea24ae6
|
|
87
|
-
webmock (3.26.4) sha256=8d8da206d217ebe6968cfb09c77f4533c23074e1432bad865f3994eacbaad50d
|
|
88
|
-
|
|
89
|
-
BUNDLED WITH
|
|
90
|
-
4.0.20
|
data/Rakefile
DELETED
data/bin/console
DELETED
data/bin/setup
DELETED
data/epok.gemspec
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
lib = File.expand_path("lib", __dir__)
|
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
-
|
|
4
|
-
require "epok/version"
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "epok"
|
|
8
|
-
spec.version = Epok::VERSION
|
|
9
|
-
spec.authors = ["Ariel Rzezak"]
|
|
10
|
-
spec.email = ["arzezak@gmail.com"]
|
|
11
|
-
|
|
12
|
-
spec.summary = "GCBA EPOk wrapper."
|
|
13
|
-
spec.description = "GCBA EPOk wrapper to query indexed geographic objects."
|
|
14
|
-
spec.homepage = "https://github.com/arzezak/epok"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
|
|
17
|
-
spec.files = `git ls-files`.split("\n")
|
|
18
|
-
spec.require_paths = ["lib"]
|
|
19
|
-
|
|
20
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
|
21
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
|
22
|
-
spec.add_development_dependency "vcr", "~> 6.0"
|
|
23
|
-
spec.add_development_dependency "webmock", "~> 3.5", ">= 3.5.1"
|
|
24
|
-
end
|
data/test/epok/api_test.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class APITest < Minitest::Test
|
|
5
|
-
include WebMock::API
|
|
6
|
-
|
|
7
|
-
def setup
|
|
8
|
-
VCR.eject_cassette
|
|
9
|
-
VCR.turn_off!
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def teardown
|
|
13
|
-
WebMock.reset!
|
|
14
|
-
VCR.turn_on!
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def test_that_a_server_error_raises
|
|
18
|
-
stub_request(:get, /epok/).to_return(status: 500, body: "boom")
|
|
19
|
-
|
|
20
|
-
error = assert_raises(Error) { Epok.search("x").first }
|
|
21
|
-
assert_match "500", error.message
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def test_that_a_timeout_raises
|
|
25
|
-
stub_request(:get, /epok/).to_timeout
|
|
26
|
-
|
|
27
|
-
assert_raises(Error) { Epok.categories }
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_that_a_non_json_body_raises
|
|
31
|
-
stub_request(:get, /epok/).to_return(status: 200, body: "<html>")
|
|
32
|
-
|
|
33
|
-
assert_raises(Error) { Epok.search("x").first }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def test_that_a_missing_object_raises_not_found
|
|
37
|
-
stub_request(:get, /getObjectContent/).to_return(status: 200, body: "{}")
|
|
38
|
-
|
|
39
|
-
assert_raises(NotFound) { Object.new("nope|1").content }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def test_that_an_object_without_a_centroid_has_no_location
|
|
43
|
-
stub_request(:get, /getObjectContent/)
|
|
44
|
-
.to_return(status: 200, body: '{"contenido": [], "ubicacion": null}')
|
|
45
|
-
|
|
46
|
-
object = Object.new("espacios_verdes_publicos|1")
|
|
47
|
-
|
|
48
|
-
assert_nil object.location
|
|
49
|
-
assert_nil object.location
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def test_that_a_failed_coordinate_conversion_raises
|
|
53
|
-
stub_request(:get, /getObjectContent/)
|
|
54
|
-
.to_return(status: 200, body: '{"ubicacion": {"centroide": "POINT (1 2)"}}')
|
|
55
|
-
stub_request(:get, /usig/)
|
|
56
|
-
.to_return(status: 200, body: '{"tipo_resultado":"Error","resultado":{"x":"","y":""}}')
|
|
57
|
-
|
|
58
|
-
assert_raises(Error) { Object.new("x|1").location }
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def test_that_not_found_is_an_error
|
|
62
|
-
assert_operator NotFound, :<, Error
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class CategoriesTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("categories")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("categories")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_categories_are_listed
|
|
14
|
-
categories = Epok.categories
|
|
15
|
-
|
|
16
|
-
assert_operator categories.size, :>, 100
|
|
17
|
-
assert categories.all? { |category| category.is_a?(Category) }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def test_that_a_category_has_an_id_and_a_name
|
|
21
|
-
pharmacies = Epok.categories.find { |category| category.id == "farmacias" }
|
|
22
|
-
|
|
23
|
-
assert_equal "Farmacias", pharmacies.name
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class CollectionTest < Minitest::Test
|
|
5
|
-
def test_that_a_collection_is_enumerable
|
|
6
|
-
collection = Collection.new { [{"id" => "a|1"}, {"id" => "a|2"}] }
|
|
7
|
-
|
|
8
|
-
assert_equal ["a|1", "a|2"], collection.map(&:id)
|
|
9
|
-
assert_equal 2, collection.count
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def test_that_a_collection_fetches_lazily_and_once
|
|
13
|
-
calls = 0
|
|
14
|
-
collection = Collection.new { calls += 1; [{"id" => "a|1"}] }
|
|
15
|
-
|
|
16
|
-
assert_equal 0, calls
|
|
17
|
-
collection.first
|
|
18
|
-
collection.to_a
|
|
19
|
-
assert_equal 1, calls
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class DatosUtilesTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("datos_utiles")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("datos_utiles")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_datos_utiles_returns_the_barrio_and_comuna
|
|
14
|
-
datos = Epok.datos_utiles(Location.new(x: -58.381570, y: -34.603738))
|
|
15
|
-
|
|
16
|
-
assert_equal "San Nicolas", datos.barrio
|
|
17
|
-
assert_equal "Comuna 1", datos.comuna
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def test_that_datos_utiles_returns_the_other_jurisdictions
|
|
21
|
-
datos = Epok.datos_utiles(Location.new(x: -58.381570, y: -34.603738))
|
|
22
|
-
|
|
23
|
-
assert_equal "3", datos.comisaria
|
|
24
|
-
assert_equal "1B", datos.comisaria_vecinal
|
|
25
|
-
assert_equal "HTAL. DR. J.M. RAMOS MEJÍA", datos.area_hospitalaria
|
|
26
|
-
assert_equal "I (Este)", datos.region_sanitaria
|
|
27
|
-
assert_equal "Distrito Escolar I", datos.distrito_escolar
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_that_outside_the_city_fields_are_nil_and_amba_is_filled
|
|
31
|
-
datos = Epok.datos_utiles(Location.new(x: -58.60, y: -34.60))
|
|
32
|
-
|
|
33
|
-
assert_nil datos.barrio
|
|
34
|
-
assert_nil datos.comuna
|
|
35
|
-
assert_equal "Tres de Febrero", datos.partido_amba
|
|
36
|
-
assert_equal "Ciudad Jardín Lomas de El Palomar", datos.localidad_amba
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
data/test/epok/geocode_test.rb
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class GeocodeTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("geocode")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("geocode")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_an_address_is_normalized_and_located
|
|
14
|
-
address = Epok.geocode("cabildo 1234").first
|
|
15
|
-
|
|
16
|
-
assert_equal "CABILDO AV. 1234, CABA", address.address
|
|
17
|
-
assert_in_delta(-58.448466, address.location.x)
|
|
18
|
-
assert_in_delta(-34.568290, address.location.y)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_that_an_address_has_a_partido_and_localidad
|
|
22
|
-
addresses = Epok.geocode("cabildo 1234")
|
|
23
|
-
|
|
24
|
-
assert_equal "CABA", addresses.first.partido
|
|
25
|
-
assert_equal "CABA", addresses.first.localidad
|
|
26
|
-
assert_equal "La Matanza", addresses[1].partido
|
|
27
|
-
assert_equal "Villa Madero", addresses[1].localidad
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_that_an_unknown_address_raises_not_found
|
|
31
|
-
error = assert_raises(NotFound) { Epok.geocode("xyzzy 999") }
|
|
32
|
-
|
|
33
|
-
assert_equal "Calle inexistente: xyzzy 999", error.message
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
data/test/epok/geocoder_test.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class GeocoderTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("geocoder")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("geocoder")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_geocoder_results_are_epok_objects
|
|
14
|
-
assert_instance_of Object, result
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def test_that_a_single_geocoder_result_has_a_name
|
|
18
|
-
assert_match "Línea D", result.name
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_that_geocoder_results_have_a_distance
|
|
22
|
-
assert_operator result.distance, :<, 500
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def test_that_geocoder_accepts_a_radius
|
|
26
|
-
near = Epok.geocoder(obelisco, "estaciones_de_subte", radius: 100)
|
|
27
|
-
far = Epok.geocoder(obelisco, "estaciones_de_subte", radius: 1000)
|
|
28
|
-
|
|
29
|
-
assert_operator near.count, :<, far.count
|
|
30
|
-
assert near.all? { |station| station.distance <= 100 }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def test_that_geocoder_accepts_several_categories
|
|
34
|
-
results = Epok.geocoder(obelisco, %w[estaciones_de_subte farmacias])
|
|
35
|
-
|
|
36
|
-
assert_equal %w[estaciones_de_subte farmacias].sort, results.map(&:category).uniq.sort
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
def result
|
|
42
|
-
Epok.geocoder(obelisco, "estaciones_de_subte").first
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def obelisco
|
|
46
|
-
Location.new(x: -58.381570, y: -34.603738)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
data/test/epok/object_test.rb
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class ObjectTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("object")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("object")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_an_object_has_a_name
|
|
14
|
-
assert_equal "BIBLIOTECA ANMAT", object.name
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def test_that_an_object_has_a_kind
|
|
18
|
-
assert_equal "Dependencias Culturales", object.kind
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_that_an_object_has_a_category
|
|
22
|
-
assert_equal "dependencias_culturales", object.category
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def test_that_an_object_has_a_normalized_address
|
|
26
|
-
assert_equal "DE MAYO AV. 869", object.normalized_address
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def test_that_an_object_has_a_location
|
|
30
|
-
location = object.location
|
|
31
|
-
|
|
32
|
-
assert_instance_of Location, location
|
|
33
|
-
assert_in_delta(-58.38, location.x, 0.01)
|
|
34
|
-
assert_in_delta(-34.61, location.y, 0.01)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def test_that_an_object_has_content
|
|
38
|
-
expected_content = {
|
|
39
|
-
"Nombre" => "BIBLIOTECA ANMAT",
|
|
40
|
-
"Categoria" => "BIBLIOTECA",
|
|
41
|
-
"Subcategoria" => "ESPECIALIZADA GUBERNAMENTAL",
|
|
42
|
-
"Teléfonos" => "54.011 4340-0800 INT. 1047 FAX 54.011 4340-0800 INT. 1048",
|
|
43
|
-
"E-Mail" => "<a href=\"mailto:NDURAND@ANMAT.GOV.AR\">NDURAND@ANMAT.GOV.AR</a>",
|
|
44
|
-
"Página WEB" => "<a href=\"http://WWW.ANMAT.GOV.AR\" target=\"_blank\">WWW.ANMAT.GOV.AR</a>",
|
|
45
|
-
"Dependencia" => "ADMINISTRACION NACIONAL DE MEDICAMENTOS Y TECNOLOGIA MEDICA ANMAT",
|
|
46
|
-
"Sector" => "PUBLICO",
|
|
47
|
-
"Dirección" => "DE MAYO AV. 869",
|
|
48
|
-
"Barrio" => "MONSERRAT",
|
|
49
|
-
"Comuna" => "Comuna 1"
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
assert_equal expected_content, object.content
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def test_that_listing_attributes_do_not_fetch
|
|
56
|
-
object = Object.new(
|
|
57
|
-
"id" => "farmacias|1082",
|
|
58
|
-
"nombre" => "Farmacia en CERRITO 342 ",
|
|
59
|
-
"clase" => "Farmacia",
|
|
60
|
-
"distancia" => "112.31"
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
VCR.eject_cassette
|
|
64
|
-
VCR.turned_off do
|
|
65
|
-
assert_equal "Farmacia en CERRITO 342", object.name
|
|
66
|
-
assert_equal "Farmacia", object.kind
|
|
67
|
-
assert_equal "farmacias", object.category
|
|
68
|
-
assert_in_delta 112.31, object.distance
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def test_that_an_object_built_from_an_id_has_no_distance
|
|
73
|
-
assert_nil object.distance
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
private
|
|
77
|
-
|
|
78
|
-
def object
|
|
79
|
-
Object.new("dependencias_culturales|1635")
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
data/test/epok/search_test.rb
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
module Epok
|
|
4
|
-
class SearchTest < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
VCR.insert_cassette("search")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def teardown
|
|
10
|
-
VCR.eject_cassette("search")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def test_that_search_results_are_epok_objects
|
|
14
|
-
assert_instance_of Object, result
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def test_that_a_single_search_result_has_a_name
|
|
18
|
-
assert_match "San Miguel de Garicoits", result.name
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_that_search_encodes_the_query
|
|
22
|
-
assert_match "Peña", Epok.search("plaza peña").first.name
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def test_that_search_filters_by_category
|
|
26
|
-
results = Epok.search("san martin", categories: "estaciones_de_subte")
|
|
27
|
-
|
|
28
|
-
assert_equal ["estaciones_de_subte"], results.map(&:category).uniq
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def test_that_search_filters_by_several_categories
|
|
32
|
-
results = Epok.search("san martin", categories: %w[estaciones_de_subte estaciones_de_ferrocarril])
|
|
33
|
-
|
|
34
|
-
assert_equal %w[estaciones_de_ferrocarril estaciones_de_subte], results.map(&:category).uniq.sort
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def test_that_search_limits_results
|
|
38
|
-
assert_equal 2, Epok.search("san martin", limit: 2).count
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def result
|
|
44
|
-
Epok.search("garicoits").first
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
data/test/epok_test.rb
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
require "test_helper"
|
|
2
|
-
|
|
3
|
-
class EpokTest < Minitest::Test
|
|
4
|
-
def test_that_search_builds_a_collection
|
|
5
|
-
assert_instance_of Epok::Collection, Epok.search("garicoits")
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def test_that_geocoder_builds_a_collection
|
|
9
|
-
obelisco = Epok::Location.new(x: -58.381570, y: -34.603738)
|
|
10
|
-
|
|
11
|
-
assert_instance_of Epok::Collection, Epok.geocoder(obelisco, "farmacias")
|
|
12
|
-
end
|
|
13
|
-
end
|
data/test/test_helper.rb
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
require "swarf/probe"
|
|
2
|
-
|
|
3
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
-
|
|
5
|
-
require "epok"
|
|
6
|
-
require "minitest/autorun"
|
|
7
|
-
require "vcr"
|
|
8
|
-
|
|
9
|
-
VCR.configure do |config|
|
|
10
|
-
config.cassette_library_dir = "test/fixtures"
|
|
11
|
-
config.hook_into :webmock
|
|
12
|
-
config.default_cassette_options = { record: :new_episodes }
|
|
13
|
-
end
|