├── .gitignore
├── .rspec
├── Gemfile
├── lib
├── version.rb
├── overpass_api_ruby.rb
├── ql.rb
├── xml.rb
└── base.rb
├── .circleci
└── config.yml
├── Rakefile
├── spec
├── integration
│ ├── ql_spec.rb
│ └── xml_spec.rb
├── unit
│ ├── ql_spec.rb
│ ├── xml_spec.rb
│ └── base_spec.rb
└── spec_helper.rb
├── CHANGELOG.md
├── Gemfile.lock
├── LICENSE
├── overpass-api-ruby.gemspec
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.gem
3 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org/'
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/lib/version.rb:
--------------------------------------------------------------------------------
1 | module OverpassAPI
2 | VERSION = '0.3.1'.freeze
3 | end
4 |
--------------------------------------------------------------------------------
/lib/overpass_api_ruby.rb:
--------------------------------------------------------------------------------
1 | require_relative 'version'
2 | require_relative 'xml'
3 | require_relative 'ql'
4 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | jobs:
4 | build:
5 | docker:
6 | - image: circleci/ruby:2.4.1
7 | steps:
8 | - checkout
9 | - run: bundle install
10 | - run: bundle exec rake spec
11 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler/gem_tasks'
2 |
3 | require 'rake'
4 | require 'rspec/core/rake_task'
5 |
6 | desc 'Run all tests'
7 | RSpec::Core::RakeTask.new(:spec) do |t|
8 | t.pattern = 'spec/**/*_spec.rb'
9 | t.rspec_opts = %w[--color --warnings]
10 | end
11 |
12 | task default: [:spec]
13 |
--------------------------------------------------------------------------------
/lib/ql.rb:
--------------------------------------------------------------------------------
1 | require_relative 'base'
2 |
3 | module OverpassAPI
4 | # builds queries in overpass ql format
5 | class QL < Base
6 | def initialize(args = {})
7 | super
8 | @maxsize = args[:maxsize]
9 | end
10 |
11 | def build_query(query)
12 | header = ''
13 | header << "[bbox:#{@bbox}]" if @bbox
14 | header << "[timeout:#{@timeout}]" if @timeout
15 | header << "[maxsize:#{@maxsize}]" if @maxsize
16 |
17 | header << '[out:json]'
18 |
19 | "#{header};#{query}"
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/integration/ql_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'overpass_api_ruby'
3 |
4 | describe OverpassAPI::QL do
5 | it 'should return the right elements' do
6 | options = { bbox: { s: -34.705448, n: -34.526562,
7 | w: -58.531471, e: -58.335159 },
8 | timeout: 900,
9 | maxsize: 10_000 }
10 |
11 | overpass = OverpassAPI::QL.new(options)
12 |
13 | ba_query = "rel['route'='subway'];(._;>;);out body;"
14 |
15 | expect(overpass.query(ba_query)[:elements]).to be_a(Array)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/xml.rb:
--------------------------------------------------------------------------------
1 | require_relative 'base'
2 |
3 | module OverpassAPI
4 | # builds queries in xml format
5 | class XML < Base
6 | def initialize(args = {})
7 | super
8 | @element_limit = args[:element_limit]
9 | end
10 |
11 | def build_query(query)
12 | bbox = @bbox ? " bbox='#{@bbox}'" : ''
13 | timeout = @timeout ? " timeout='#{@timeout}'" : ''
14 | element_limit = @element_limit ? " element-limit='#{@element_limit}'" : ''
15 |
16 | "" \
17 | "#{query}"
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | CHANGELOG
2 | =========
3 | v 0.3.1
4 | -------
5 | - Clean up / refactor per rubocop suggestions
6 |
7 | v 0.3
8 | -----
9 | - Use POST instead of GET.
10 | - Update rack to version 2.0.6 because of a GitHub vulnerability alert.
11 |
12 | v 0.2.3
13 | --------
14 | Removes param `data` from ENDPOINT constant (Issue #5)
15 |
16 | v 0.2.2
17 | -------
18 | Fixes `maxsize` option in the `XML` class. (Issue #4)
19 |
20 | v 0.2
21 | -----
22 | BREAKING CHANGES
23 | The addition of XML and QL classes breaks the compatibility with previous versions. Also, the `element_limit` option was deprecated, so now it's named `maxsize`. Check the examples.
24 |
--------------------------------------------------------------------------------
/spec/integration/xml_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'overpass_api_ruby'
3 |
4 | describe OverpassAPI::XML do
5 | it 'should return the requested elements' do
6 | options = { bbox: { s: -34.705448, n: -34.526562,
7 | w: -58.531471, e: -58.335159 },
8 | timeout: 900,
9 | element_limit: 100_000 }
10 |
11 | overpass = OverpassAPI::XML.new(options)
12 |
13 | ba_query = "" \
14 | "" \
15 | " "
16 |
17 | expect(overpass.query(ba_query)[:elements]).to be_a(Array)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/unit/ql_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'overpass_api_ruby'
3 |
4 | describe OverpassAPI::QL do
5 | it 'should return the right built query when no opts are passed' do
6 | overpass = OverpassAPI::QL.new
7 | built_query = overpass.build_query('a query')
8 |
9 | expect(built_query).to eq '[out:json];a query'
10 | end
11 |
12 | it 'should set the right opts' do
13 | opts = { bbox: { s: 1, n: 2, w: 3, e: 4 },
14 | timeout: 1000,
15 | maxsize: 333 }
16 |
17 | overpass = OverpassAPI::QL.new(opts)
18 | built_query = overpass.build_query('a query')
19 |
20 | expected_built_query = '[bbox:1,3,2,4][timeout:1000]' \
21 | '[maxsize:333][out:json];a query'
22 | expect(built_query).to eq expected_built_query
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/base.rb:
--------------------------------------------------------------------------------
1 | require 'httpi'
2 | require 'json'
3 |
4 | module OverpassAPI
5 | # base class, ql and xml extend this
6 | class Base
7 | DEFAULT_ENDPOINT = 'http://overpass-api.de/api/interpreter'.freeze
8 |
9 | def initialize(args = {})
10 | bbox = args[:bbox]
11 | bounding_box(bbox[:s], bbox[:n], bbox[:w], bbox[:e]) if bbox
12 |
13 | @endpoint = args[:endpoint] || DEFAULT_ENDPOINT
14 | @timeout = args[:timeout]
15 | end
16 |
17 | def bounding_box(south, north, west, east)
18 | @bbox = "#{south},#{west},#{north},#{east}"
19 | end
20 |
21 | def query(query)
22 | perform build_query(query)
23 | end
24 |
25 | def raw_query(query)
26 | perform query
27 | end
28 |
29 | private
30 |
31 | def perform(query)
32 | r = HTTPI::Request.new(url: @endpoint, body: query)
33 | JSON.parse(HTTPI.post(r).body, symbolize_names: true)
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/unit/xml_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'overpass_api_ruby'
3 |
4 | describe OverpassAPI::XML do
5 | it 'should return the right built query when no opts are passed' do
6 | overpass = OverpassAPI::XML.new
7 | built_query = overpass.build_query('a query')
8 |
9 | expect(built_query).to eq "a query" \
10 | ''
11 | end
12 |
13 | it 'should set the right opts' do
14 | opts = { bbox: { s: 1, n: 2, w: 3, e: 4 },
15 | timeout: 1000,
16 | element_limit: 333 }
17 |
18 | overpass = OverpassAPI::XML.new(opts)
19 | built_query = overpass.build_query('a query')
20 |
21 | expected_built_query = "" \
23 | 'a query'
24 | expect(built_query).to eq expected_built_query
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | overpass-api-ruby (0.3)
5 | httpi (~> 2.4.0)
6 |
7 | GEM
8 | remote: https://rubygems.org/
9 | specs:
10 | coderay (1.1.1)
11 | diff-lcs (1.3)
12 | httpi (2.4.2)
13 | rack
14 | socksify
15 | method_source (0.8.2)
16 | pry (0.10.4)
17 | coderay (~> 1.1.0)
18 | method_source (~> 0.8.1)
19 | slop (~> 3.4)
20 | rack (2.0.6)
21 | rake (12.0.0)
22 | rspec (3.6.0)
23 | rspec-core (~> 3.6.0)
24 | rspec-expectations (~> 3.6.0)
25 | rspec-mocks (~> 3.6.0)
26 | rspec-core (3.6.0)
27 | rspec-support (~> 3.6.0)
28 | rspec-expectations (3.6.0)
29 | diff-lcs (>= 1.2.0, < 2.0)
30 | rspec-support (~> 3.6.0)
31 | rspec-mocks (3.6.0)
32 | diff-lcs (>= 1.2.0, < 2.0)
33 | rspec-support (~> 3.6.0)
34 | rspec-support (3.6.0)
35 | slop (3.6.0)
36 | socksify (1.7.1)
37 |
38 | PLATFORMS
39 | ruby
40 |
41 | DEPENDENCIES
42 | bundler (~> 1.3)
43 | overpass-api-ruby!
44 | pry (~> 0.10)
45 | rake (~> 12.0)
46 | rspec (~> 3.6)
47 |
48 | BUNDLED WITH
49 | 1.17.2
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Bruno Salerno
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/overpass-api-ruby.gemspec:
--------------------------------------------------------------------------------
1 | lib = File.expand_path('lib', __dir__)
2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3 | require 'version'
4 |
5 | Gem::Specification.new do |spec|
6 | spec.name = 'overpass-api-ruby'
7 | spec.version = OverpassAPI::VERSION
8 | spec.authors = ['Bruno Salerno']
9 | spec.email = ['br.salerno@gmail.com']
10 | spec.description = 'A Ruby wrapper for OpenStreetMap Overpass API'
11 | spec.summary = 'This gem will allow you to perform queries to'\
12 | 'OSM Overpass API using QL or XML'
13 | spec.homepage = 'https://github.com/BrunoSalerno/overpass-api-ruby'
14 | spec.license = 'MIT'
15 |
16 | spec.files = `git ls-files`.split($RS)
17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19 | spec.require_paths = ['lib']
20 |
21 | spec.add_runtime_dependency 'httpi', '~> 2.4'
22 |
23 | spec.add_development_dependency 'bundler', '~> 1.3'
24 | spec.add_development_dependency 'pry', '~> 0.10'
25 | spec.add_development_dependency 'rake', '~> 12.0'
26 | spec.add_development_dependency 'rspec', '~> 3.6'
27 | end
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Overpass API Ruby [](https://circleci.com/gh/BrunoSalerno/overpass-api-ruby)
2 | =================
3 |
4 | A Ruby wrapper for OpenStreetMap Overpass API. Supports both QL and XML.
5 |
6 | Note: Version 0.2 introduces breaking changes. Check the file CHANGELOG.md.
7 |
8 | Install
9 | -------
10 |
11 | `gem install overpass-api-ruby`
12 |
13 | or add `gem 'overpass-api-ruby'` to your Gemfile
14 |
15 | Usage
16 | -----
17 |
18 | Using XML:
19 |
20 | ```ruby
21 | require 'overpass_api_ruby'
22 |
23 | options={:bbox => {:s => -34.705448, :n => -34.526562,
24 | :w => -58.531471, :e => -58.335159},
25 | :timeout => 900,
26 | :element_limit => 1073741824}
27 |
28 | overpass = OverpassAPI::XML.new(options)
29 |
30 | query = "" <<
31 | " "
32 |
33 | response = overpass.query(query)
34 | ```
35 |
36 | Using QL:
37 |
38 | ```ruby
39 | require 'overpass_api_ruby'
40 |
41 | options={:bbox => {:s => -34.705448, :n => -34.526562,
42 | :w => -58.531471, :e => -58.335159},
43 | :timeout => 900,
44 | :maxsize => 1073741824}
45 |
46 | overpass = OverpassAPI::QL.new(options)
47 |
48 | query = "rel['route'='subway'];(._;>;);out body;"
49 |
50 | response = overpass.query(query)
51 | ```
52 |
53 | Common options on instantiation
54 | ------------------------
55 | ```
56 | bbox Hash. Global bounding box.
57 | endpoint String.
58 | Defaults to http://overpass-api.de/api/interpreter
59 | timeout Integer.
60 | ```
61 |
62 | Specific options on instantiation
63 | ------------------------
64 | QL
65 | ```
66 | maxsize Integer.
67 | ```
68 |
69 | XML
70 | ```
71 | element_limit Integer.
72 | ```
73 |
74 | See [Overpass API](http://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide)
75 |
76 | Public methods
77 | --------------
78 |
79 | Both `QL` and `XML` classes have the same public methods:
80 |
81 | ```ruby
82 | query () Performs the query passed using the global values set on instantiation.
83 |
84 | raw_query () The whole query must be passed.
85 |
86 | buid_query () Returns a String containing the whole query.
87 |
88 | bounding_box (s,n,w,e) Defines the global bounding box.
89 | ```
90 |
91 | Test
92 | ----
93 |
94 | Run `rake spec`
95 |
96 | License
97 | -------
98 | MIT.
99 |
--------------------------------------------------------------------------------
/spec/unit/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'overpass_api_ruby'
3 | require 'httpi'
4 |
5 | # rubocop:disable Metrics/BlockLength
6 | describe OverpassAPI::Base do
7 | it 'should return the default endpoint' do
8 | expect(OverpassAPI::Base::DEFAULT_ENDPOINT).to eq 'http://overpass-api.de/api/interpreter'
9 | base = OverpassAPI::Base.new
10 | expect(
11 | base.instance_variable_get('@endpoint')
12 | ).to eq OverpassAPI::Base::DEFAULT_ENDPOINT
13 | end
14 |
15 | it 'should set the right args' do
16 | opts = { bbox: { s: 1, n: 2, w: 3, e: 4 },
17 | endpoint: 'a.endpoint.com',
18 | timeout: 1000 }
19 |
20 | base = OverpassAPI::Base.new(opts)
21 |
22 | expect(base.instance_variable_get('@bbox')).to eq '1,3,2,4'
23 | expect(base.instance_variable_get('@endpoint')).to eq 'a.endpoint.com'
24 | expect(base.instance_variable_get('@timeout')).to eq 1000
25 | end
26 |
27 | it 'should set the bounding box' do
28 | base = OverpassAPI::Base.new
29 | base.bounding_box(10, 20, 30, 40)
30 |
31 | expect(base.instance_variable_get('@bbox')).to eq '10,30,20,40'
32 | end
33 |
34 | it 'should try to perform the query' do
35 | base = OverpassAPI::Base.new
36 |
37 | query = 'a query'
38 | built_query = 'built_query'
39 | expected_response = 'a response'
40 |
41 | allow(base).to receive(:perform).and_return(expected_response)
42 | allow(base).to receive(:build_query).and_return(built_query)
43 |
44 | expect(base).to receive(:build_query).with(query)
45 | expect(base).to receive(:perform).with(built_query)
46 |
47 | response = base.query(query)
48 |
49 | expect(response).to eq expected_response
50 | end
51 |
52 | it 'should try to perform a raw query' do
53 | base = OverpassAPI::Base.new
54 |
55 | query = 'as query'
56 | expected_response = 'a response'
57 |
58 | allow(base).to receive(:perform).and_return(expected_response)
59 | expect(base).to receive(:perform).with(query)
60 |
61 | response = base.raw_query(query)
62 |
63 | expect(response).to eq expected_response
64 | end
65 |
66 | it 'should try to perform an http request' do
67 | base = OverpassAPI::Base.new
68 |
69 | query = 'a query'
70 | request = 'a request'
71 | body = { key: 'value' }
72 |
73 | allow(HTTPI::Request).to receive(:new).and_return(request)
74 | expect(
75 | HTTPI::Request
76 | ).to receive(:new).with(
77 | url: OverpassAPI::Base::DEFAULT_ENDPOINT,
78 | body: query
79 | )
80 |
81 | allow(
82 | HTTPI
83 | ).to receive(:post).and_return(
84 | OpenStruct.new(body: body.to_json)
85 | )
86 | expect(HTTPI).to receive(:post).with(request)
87 |
88 | response = base.raw_query(query)
89 | expect(response).to eq body
90 | end
91 | end
92 | # rubocop:enable Metrics/BlockLength
93 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rspec --init` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause
4 | # this file to always be loaded, without a need to explicitly require it in any
5 | # files.
6 | #
7 | # Given that it is always loaded, you are encouraged to keep this file as
8 | # light-weight as possible. Requiring heavyweight dependencies from this file
9 | # will add to the boot time of your test suite on EVERY test run, even for an
10 | # individual file that may not need all of that loaded. Instead, consider making
11 | # a separate helper file that requires the additional dependencies and performs
12 | # the additional setup, and require it from the spec files that actually need
13 | # it.
14 | #
15 | # The `.rspec` file also contains a few flags that are not defaults but that
16 | # users commonly want.
17 | #
18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19 |
20 | RSpec.configure do |config|
21 | # rspec-expectations config goes here. You can use an alternate
22 | # assertion/expectation library such as wrong or the stdlib/minitest
23 | # assertions if you prefer.
24 | config.expect_with :rspec do |expectations|
25 | # This option will default to `true` in RSpec 4. It makes the `description`
26 | # and `failure_message` of custom matchers include text for helper methods
27 | # defined using `chain`, e.g.:
28 | # be_bigger_than(2).and_smaller_than(4).description
29 | # # => "be bigger than 2 and smaller than 4"
30 | # ...rather than:
31 | # # => "be bigger than 2"
32 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33 | end
34 |
35 | # rspec-mocks config goes here. You can use an alternate test double
36 | # library (such as bogus or mocha) by changing the `mock_with` option here.
37 | config.mock_with :rspec do |mocks|
38 | # Prevents you from mocking or stubbing a method that does not exist on
39 | # a real object. This is generally recommended, and will default to
40 | # `true` in RSpec 4.
41 | mocks.verify_partial_doubles = false
42 | end
43 |
44 | # The settings below are suggested to provide a good initial experience
45 | # with RSpec, but feel free to customize to your heart's content.
46 |
47 | # These two settings work together to allow you to limit a spec run
48 | # to individual examples or groups you care about by tagging them with
49 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples
50 | # get run.
51 | # config.filter_run :focus
52 | # config.run_all_when_everything_filtered = true
53 |
54 | # Allows RSpec to persist some state between runs in order to support
55 | # the `--only-failures` and `--next-failure` CLI options. We recommend
56 | # you configure your source control system to ignore this file.
57 | # config.example_status_persistence_file_path = "spec/examples.txt"
58 |
59 | # Limits the available syntax to the non-monkey patched syntax that is
60 | # recommended. For more details, see:
61 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
62 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
63 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
64 | # config.disable_monkey_patching!
65 |
66 | # This setting enables warnings. It's recommended, but in some cases may
67 | # be too noisy due to issues in dependencies.
68 | # config.warnings = true
69 |
70 | # Many RSpec users commonly either run the entire suite or an individual
71 | # file, and it's useful to allow more verbose output when running an
72 | # individual spec file.
73 | # if config.files_to_run.one?
74 | # Use the documentation formatter for detailed output,
75 | # unless a formatter has already been configured
76 | # (e.g. via a command-line flag).
77 | # config.default_formatter = 'doc'
78 | # end
79 |
80 | # Print the 10 slowest examples and example groups at the
81 | # end of the spec run, to help surface which specs are running
82 | # particularly slow.
83 | # config.profile_examples = 10
84 |
85 | # Run specs in random order to surface order dependencies. If you find an
86 | # order dependency and want to debug it, you can fix the order by providing
87 | # the seed, which is printed after each run.
88 | # --seed 1234
89 | # config.order = :random
90 |
91 | # Seed global randomization in this process using the `--seed` CLI option.
92 | # Setting this allows you to use `--seed` to deterministically reproduce
93 | # test failures related to randomization by passing the same `--seed` value
94 | # as the one that triggered the failure.
95 | # Kernel.srand config.seed
96 | end
97 |
--------------------------------------------------------------------------------