arcrest 0.0.0.pre → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4facbf131295458bba59afadece248118b806cf9
4
- data.tar.gz: 4453da319fa914ff6a03e9b42caf6fd2c6720b6f
3
+ metadata.gz: 948887626e3cbf6c38a60ab4d3f3f96f38815a64
4
+ data.tar.gz: ee36b210de6e5354e2afae62ec6b3ba3bdbb44d4
5
5
  SHA512:
6
- metadata.gz: 6f78ad5e3bd3d33f9f75da848670163a8a3b1fd07c541046e8125de5f61b99723005b680dc2eaabd55674fc9b5e4c78c611039e75ee63d9f52fac42f27b2ab9a
7
- data.tar.gz: e08922265ac4e258c8ba4ac1cdd5e45a98092949f88b9398e9614637aebfc2854cd51cde97b2ccffb3100a890fb440e19dc47bcd11553f1251be8849e093c2a6
6
+ metadata.gz: a3bfa45f4ea1fa30629e216122fe40783d3519b78e9e592e6e14ea41082b0e88d18bc8e284f101da40a07610ec69154772a99256b9748cf30f62e4905d89edbd
7
+ data.tar.gz: 736154f7a57441c74bb37234b500a3126c258ce173adc4aa5e0a7b5af2ca2be38f7c55d7aad7952cace2f82337d7529a638538ff238e02cf630b7f578ccf9509
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
+ --require spec_helper
data/.travis.yml CHANGED
@@ -2,9 +2,8 @@ sudo: false
2
2
  language: ruby
3
3
 
4
4
  rvm:
5
- - 2.3.0
6
- - 2.2.0
7
- - 2.1
5
+ - 2.3.1
6
+ - 2.2.5
8
7
 
9
8
  before_install: gem install bundler -v 1.12.5
10
9
 
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ notification :gntp
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec' do
4
+ watch(%r{^lib/(.+).rb$}) do |m| # watch /lib/ files
5
+ "spec/#{m[1]}_spec.rb"
6
+ end
7
+
8
+ watch(%r{^spec/(.+).rb$}) do |m| # watch /spec/ files
9
+ "spec/#{m[1]}.rb"
10
+ end
11
+
12
+ watch('spec/spec_helper.rb') { 'spec' }
13
+ end
data/README.md CHANGED
@@ -1,19 +1,113 @@
1
- # Arcrest
1
+ # ArcREST
2
+ [![Build status](https://secure.travis-ci.org/MatzFan/ArcREST.svg)](http://travis-ci.org/MatzFan/ArcREST)
3
+ [![Gem Version](https://badge.fury.io/rb/arcrest.svg)](http://badge.fury.io/rb/arcrest)
4
+
5
+ Ruby Gem wrapper around the [ArcGIS REST API](http://services.arcgisonline.com/arcgis/sdk/rest/)
6
+
7
+ ## Requirements
8
+
9
+ bundler
10
+
11
+
12
+ ## Current Limitations
13
+
14
+ API FeatureServer query capabilities only at present. Unauthenticated calls only (please raise an issue if you wish this to be supported)
2
15
 
3
- Placeholder for arcrest Ruby Gem
4
16
 
5
17
  ## Installation
6
18
 
19
+ Add this line to your application's Gemfile:
20
+
21
+ $ gem 'arcrest'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
7
29
  $ gem install arcrest
8
30
 
31
+
9
32
  ## Usage
10
33
 
11
- TODO: Write usage instructions here
34
+ The API defines a [resource heirarchy](http://services.arcgisonline.com/arcgis/sdk/rest/#/Resource_hierarchy) which includes a Catalog of Services (MapServer or FeatureServer). Services have one or more Layers and Layers have Features, which may be queried in various ways, including by spatial coordinates.
35
+
36
+ ```ruby
37
+ require 'arcrest'
38
+
39
+ catalog = ArcREST::Catalog.new('http://rmgsc.cr.usgs.gov/arcgis/rest/services')
40
+ puts catalog.services
41
+ #=> {"name"=>"cwqdr_main", "type"=>"MapServer"}
42
+ #=> {"name"=>"ecosys_Africa", "type"=>"MapServer"}
43
+ #=> {"name"=>"ecosys_SA", "type"=>"MapServer"}
44
+ #=> ...
45
+
46
+ service = ArcREST::Service.new('http://rmgsc.cr.usgs.gov/arcgis/rest/services/geomac_fires/FeatureServer')
47
+ puts service.layers
48
+ #=> {"id"=>1, "name"=>"Large Fire Points"}
49
+ #=> {"id"=>2, "name"=>"Fire Perimeters"}
50
+ #=> {"id"=>3, "name"=>"MODIS Thermal Satellite"}
51
+ #=> {"id"=>4, "name"=>"Inactive Fire Perimeters"}
52
+
53
+ layer = ArcREST::Layer.new("#{service.url}/2")
54
+ puts layer.name
55
+ #=> Fire Perimeters
56
+ puts layer.type
57
+ #=> Feature Layer
58
+ puts layer.count
59
+ #=> 14 # count of the layer's features
60
+ puts layer.object_ids.inspect
61
+ #=> [681, 682, 688, 690, 614, 618, 619, 653, 683, 684, 685, 686, 687, 689]
62
+ puts layer.fields
63
+ #=> {"name"=>"objectid", "type"=>"esriFieldTypeOID", "alias"=>"OBJECTID", "domain"=>nil, "editable"=>false, "nullable"=>false}
64
+ #=> {"name"=>"agency", "type"=>"esriFieldTypeString", "alias"=>"agency", "domain"=>nil, "editable"=>true, "nullable"=>true, "length"=>15}
65
+ #=> ...
66
+ ```
67
+
68
+ Once you have a Layer object, you can query it's features. The [documention](http://services.arcgisonline.com/arcgis/sdk/rest/index.html#/Query_Feature_Service_Layer/) shows the possibilities. Here is a very simple example:
69
+
70
+ ```ruby
71
+ features = layer.features(where: "agency='BLM'", returnGeometry: false)
72
+ puts features.count
73
+ #=> 2
74
+ puts features.first
75
+ #=> {"objectid"=>690, "agency"=>"BLM", "comments"=>" ", "active"=>"Y"...
76
+ ```
77
+
78
+ ```features``` takes an options hash of API call params. Invalid key values raise an error. Valid params for the server can be listed like this:
79
+ ```ruby
80
+ puts layer.valid_opts.inspect
81
+ #=> ["dbVersion", "distance", "geometry", "geometryPrecision"...
82
+ ```
83
+ or by consulting the [docs](http://services.arcgisonline.com/arcgis/sdk/rest/index.html#/Query_Feature_Service_Layer/). One default is set: ```outFields: '*'``` - which requests data for all fields.
84
+
85
+
86
+ The ```:where``` key is used with any valid SQL to query the layer fields. The default is '1=1' which returns all records (up to the ```@max_record_count``` value, usually 1,000). An InvalidQuery error is raised if the server gives a 400 error of this form:
87
+ ```json
88
+ {
89
+ "error": {
90
+ "code": 400,
91
+ "message": "Unable to complete operation.",
92
+ "details": [
93
+ "Unable to perform query operation.",
94
+ "Invalid query"
95
+ ]
96
+ }
97
+ }
98
+ ```
99
+
100
+
101
+ ## Specification & Tests
102
+
103
+ Full specification documentation is available for each build at [Travis](https://travis-ci.org/MatzFan/ArcREST). To run the tests yourself clone this repo and run:
104
+
105
+ $ rake spec
12
106
 
13
107
 
14
108
  ## Contributing
15
109
 
16
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/arcrest. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
110
+ Bug reports and pull requests are welcome on GitHub at https://github.com/MatzFan/arcrest
17
111
 
18
112
 
19
113
  ## License
data/arcrest.gemspec CHANGED
@@ -24,4 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency 'bundler', '~> 1.12'
25
25
  spec.add_development_dependency 'rake', '~> 10.0'
26
26
  spec.add_development_dependency 'rspec', '~> 3.0'
27
+ spec.add_development_dependency 'guard', '~> 2.14'
28
+ spec.add_development_dependency 'guard-rspec', '~> 4.7'
29
+ spec.add_development_dependency 'ruby_gntp', '~> 0.3' # guard notifications
27
30
  end
@@ -0,0 +1,20 @@
1
+ # adds ability to dynamically set instance vars & accessors
2
+ module Attributable
3
+ def create_method(name, &block)
4
+ self.class.send(:define_method, name.to_sym, &block)
5
+ end
6
+
7
+ def create_setter(m)
8
+ create_method("#{m}=".to_sym) { |v| instance_variable_set("@#{m}", v) }
9
+ end
10
+
11
+ def create_getter(m)
12
+ create_method(m.to_sym) { instance_variable_get("@#{m}") }
13
+ end
14
+
15
+ def set_attr(method, value)
16
+ create_setter(method)
17
+ send "#{method}=".to_sym, value
18
+ create_getter(method)
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module ArcREST
2
+ # a catalog of services
3
+ class Catalog < Server
4
+ attr_reader :folders, :services
5
+
6
+ def initialize(url)
7
+ super
8
+ @services = services
9
+ end
10
+
11
+ def folders
12
+ @json['folders']
13
+ end
14
+
15
+ def services
16
+ @json['services']
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,91 @@
1
+ module ArcREST
2
+ class InvalidOption < StandardError; end
3
+ class InvalidQuery < StandardError; end
4
+ # a layer
5
+ class Layer < Server
6
+ include Attributable
7
+
8
+ ERR = 'error'.freeze
9
+ ATTRIBUTES = %w(id name type drawing_info fields max_record_count).freeze
10
+ DEFAULT_PARAMS = { where: '1=1', outFields: '*' }.freeze
11
+ PARAMS = %w(distance geometry geometryType inSR objectIds
12
+ outFields outSR relationParam returnDistinceValues
13
+ returnIdsOnly spatialRel time where).freeze
14
+ PARAMS_SP1 = %w(returnCountOnly).freeze
15
+ PARAMS_10_1 = %w(dbVersion geometryPrecision groupByFieldsForStatistics
16
+ maxAllowableOffset multiPatchOption orderByFields
17
+ outStatistics returnGeometry returnM returnZ).freeze
18
+ PARAMS_10_3 = %w(returnExtentOnly resultOffset resultRecordCount).freeze
19
+
20
+ attr_reader :valid_params # other accessors set in constructor
21
+
22
+ def initialize(url)
23
+ super
24
+ generate_attributes # dynamically create & assign values to attributes :)
25
+ end
26
+
27
+ def count
28
+ @version > 10 ? count_only_true : object_ids.count # v10.1 onwards
29
+ end
30
+
31
+ def object_ids # care - must specify outFields to overide default '*'
32
+ query(outFields: nil, returnIdsOnly: true)['objectIds']
33
+ end
34
+
35
+ def features(options = {})
36
+ query(options)['features']
37
+ end
38
+
39
+ def valid_opts
40
+ return PARAMS if @version < 10 || @version == 10.0
41
+ return (PARAMS + PARAMS_SP1).sort if @version < 10.1
42
+ return (PARAMS + PARAMS_SP1 + PARAMS_10_1).sort if @version < 10.2
43
+ (PARAMS + PARAMS_SP1 + PARAMS_10_1 + PARAMS_10_3).sort
44
+ end
45
+
46
+ private
47
+
48
+ def generate_attributes
49
+ ATTRIBUTES.each { |name| set_attr(name, json_value(name)) }
50
+ end
51
+
52
+ def json_value(name)
53
+ @json[camelify(name)]
54
+ end
55
+
56
+ def camelify(name)
57
+ words = name.split('_')
58
+ words[1..-1].map(&:capitalize).unshift(words.first).join
59
+ end
60
+
61
+ def query(options)
62
+ validate(options.keys.map(&:to_s).sort)
63
+ valid_resp(build_uri, DEFAULT_PARAMS.merge(options))
64
+ end
65
+
66
+ def valid_resp(uri, opts)
67
+ raise InvalidQuery, m(opts) if (resp = json(uri, opts)).keys.include? ERR
68
+ resp
69
+ end
70
+
71
+ def m(options)
72
+ "The following query parameters resulted in a 400 response:\n#{options}"
73
+ end
74
+
75
+ def validate(keys)
76
+ keys.all? { |k| raise InvalidOption, msg(k) unless valid_opts.include? k }
77
+ end
78
+
79
+ def msg(key)
80
+ "'#{key}' is an invalid option, valid query options are:\n#{PARAMS}"
81
+ end
82
+
83
+ def count_only_true
84
+ query(returnCountOnly: true)['count']
85
+ end
86
+
87
+ def build_uri
88
+ URI::HTTP.build(host: @uri.host, path: "#{@uri.path}/query")
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,48 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module ArcREST
5
+ # adds metadata method
6
+ class Server
7
+ REGEX = %r{^\/arcgis\/rest\/services}i
8
+ BAD_ENDPOINT = 'Invalid ArcGIS endpoint'.freeze
9
+
10
+ attr_reader :url, :json, :version
11
+
12
+ def initialize(url)
13
+ @url = url
14
+ @uri = uri
15
+ @server_uri = server_uri
16
+ @json = json(@uri)
17
+ @version = version
18
+ end
19
+
20
+ def json(uri, options = {})
21
+ JSON.parse get(uri, options)
22
+ end
23
+
24
+ def version
25
+ json(server_uri)['currentVersion'] # subclasses use server uri
26
+ end
27
+
28
+ protected
29
+
30
+ def uri
31
+ raise ArgumentError, BAD_ENDPOINT if (URI(@url).path =~ REGEX) != 0
32
+ URI @url
33
+ end
34
+
35
+ def server_uri
36
+ URI::HTTP.build(host: @uri.host, path: '/arcgis/rest/services')
37
+ end
38
+
39
+ def add_json_param_to(hash)
40
+ { f: 'pjson' }.merge(hash) # 'pjson' guarantees id's unique
41
+ end
42
+
43
+ def get(uri, options = {})
44
+ uri.query = URI.encode_www_form(add_json_param_to(options))
45
+ Net::HTTP.get uri
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ module ArcREST
2
+ # a FeatureService or a MapService
3
+ class Service < Server
4
+ attr_reader :max_record_count, :capabilities, :layers
5
+
6
+ def initialize(url)
7
+ super
8
+ @max_record_count = max_record_count # may be nil
9
+ @capabilities = capabilities # may be empty
10
+ @layers = layers # may be empty
11
+ end
12
+
13
+ def max_record_count
14
+ @json['maxRecordCount']
15
+ end
16
+
17
+ def capabilities
18
+ @json['capabilities'] ? @json['capabilities'].split(',') : nil
19
+ end
20
+
21
+ def layers
22
+ @json['layers']
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module ArcREST
2
- VERSION = '0.0.0.pre'.freeze
2
+ VERSION = '0.0.1'.freeze
3
3
  end
data/lib/arcrest.rb CHANGED
@@ -1,6 +1,9 @@
1
+ require 'arcrest/attributable' # module
1
2
  require 'arcrest/version'
3
+ require 'arcrest/server'
4
+ require 'arcrest/catalog'
5
+ require 'arcrest/service'
6
+ require 'arcrest/layer'
2
7
 
3
8
  # namespace
4
- module ArcREST
5
- # Your code goes here...
6
- end
9
+ module ArcRest; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arcrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.pre
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruce Steedman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-27 00:00:00.000000000 Z
11
+ date: 2016-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,48 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby_gntp
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.3'
55
97
  description: Wrapper for ArcGIS REST API
56
98
  email:
57
99
  - bruce.steedman@gmail.com
@@ -63,6 +105,7 @@ files:
63
105
  - ".rspec"
64
106
  - ".travis.yml"
65
107
  - Gemfile
108
+ - Guardfile
66
109
  - LICENSE.txt
67
110
  - README.md
68
111
  - Rakefile
@@ -70,6 +113,11 @@ files:
70
113
  - bin/console
71
114
  - bin/setup
72
115
  - lib/arcrest.rb
116
+ - lib/arcrest/attributable.rb
117
+ - lib/arcrest/catalog.rb
118
+ - lib/arcrest/layer.rb
119
+ - lib/arcrest/server.rb
120
+ - lib/arcrest/service.rb
73
121
  - lib/arcrest/version.rb
74
122
  homepage: https://github.com/MatzFan/arcrest
75
123
  licenses:
@@ -86,12 +134,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
134
  version: '0'
87
135
  required_rubygems_version: !ruby/object:Gem::Requirement
88
136
  requirements:
89
- - - ">"
137
+ - - ">="
90
138
  - !ruby/object:Gem::Version
91
- version: 1.3.1
139
+ version: '0'
92
140
  requirements: []
93
141
  rubyforge_project:
94
- rubygems_version: 2.6.2
142
+ rubygems_version: 2.5.1
95
143
  signing_key:
96
144
  specification_version: 4
97
145
  summary: Wrapper for ArcGIS REST API