reso_transport 1.5.5 → 1.5.7
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/.gitignore +2 -0
- data/.gitpod.yml +2 -0
- data/.rubocop.yml +33 -0
- data/README.md +27 -9
- data/bin/console +10 -10
- data/bin/rake +29 -0
- data/lib/reso_transport.rb +22 -34
- data/lib/reso_transport/authentication/fetch_token_auth.rb +30 -11
- data/lib/reso_transport/base_metadata.rb +61 -0
- data/lib/reso_transport/client.rb +33 -17
- data/lib/reso_transport/datasystem.rb +22 -0
- data/lib/reso_transport/datasystem_parser.rb +26 -0
- data/lib/reso_transport/entity_set.rb +2 -4
- data/lib/reso_transport/entity_type.rb +11 -13
- data/lib/reso_transport/metadata.rb +12 -30
- data/lib/reso_transport/metadata_cache.rb +4 -5
- data/lib/reso_transport/metadata_parser.rb +31 -22
- data/lib/reso_transport/query.rb +44 -42
- data/lib/reso_transport/resource.rb +22 -9
- data/lib/reso_transport/version.rb +1 -1
- data/reso_transport.gemspec +20 -20
- metadata +20 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49293478c0827ccb4bdca1bb6c9974900f8c0c16853b247487120a0ed3bb79df
|
4
|
+
data.tar.gz: c9d8c93979377ed18d22a179bae44175961b44e8641eb091930f99542d1e610f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4464fe0a9aa0006f25c5eab29dab8422401ac2ebf435b712e65d5727e43606bb0df4fdf895e5a1d6a1e3e44d4937d19c42389577d28568351832ccae64d55ebb
|
7
|
+
data.tar.gz: 729d643455ddd8e7a827ddc6aea2a8512f93bc65a3e469993da5d2cd5085ecdc5eed4befee4f376cd9986f51a81d363fdeb042a1f8f51e2e51d7230f265c2d7a
|
data/.gitignore
CHANGED
data/.gitpod.yml
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.6
|
3
|
+
|
4
|
+
Layout/FirstHashElementIndentation:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Layout/MultilineMethodCallIndentation:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 20
|
12
|
+
|
13
|
+
Metrics/BlockLength:
|
14
|
+
Exclude:
|
15
|
+
- test/**/*
|
16
|
+
|
17
|
+
Metrics/ClassLength:
|
18
|
+
Max: 150
|
19
|
+
|
20
|
+
Metrics/MethodLength:
|
21
|
+
Max: 15
|
22
|
+
|
23
|
+
Metrics/ModuleLength:
|
24
|
+
Max: 150
|
25
|
+
|
26
|
+
Style/ColonMethodCall:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Style/Documentation:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/FrozenStringLiteralComment:
|
33
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
[](https://gitpod.io/#https://github.com/wrstudios/reso_transport)
|
2
|
+
[](https://badge.fury.io/rb/reso_transport)
|
3
|
+
|
1
4
|
# ResoTransport
|
2
5
|
|
3
6
|
A Ruby gem for connecting to and interacting with RESO WebAPI services. Learn more about what that is by checking out the [RESO WebAPI](https://www.reso.org/reso-web-api/) Documentation.
|
@@ -51,7 +54,7 @@ Or you can set a logger for each specific instance of a client which can be usef
|
|
51
54
|
|
52
55
|
### Getting Connected
|
53
56
|
|
54
|
-
There are 2 strategies for authentication.
|
57
|
+
There are 2 strategies for authentication.
|
55
58
|
|
56
59
|
**Bearer Token**
|
57
60
|
|
@@ -60,7 +63,8 @@ It's simple to use a static access token if your token never expires:
|
|
60
63
|
```ruby
|
61
64
|
@client = ResoTransport::Client.new({
|
62
65
|
md_file: METADATA_CACHE,
|
63
|
-
endpoint: ENDPOINT_URL
|
66
|
+
endpoint: ENDPOINT_URL,
|
67
|
+
use_replication_endpoint: false # this is the default and can be ommitted
|
64
68
|
authentication: {
|
65
69
|
access_token: TOKEN,
|
66
70
|
token_type: "Bearer" # this is the default and can be ommitted
|
@@ -89,7 +93,8 @@ If the connection requires requesting a new token periodically, it's easy to pro
|
|
89
93
|
|
90
94
|
This will pre-fetch a token from the provided endpoint when the current token is either non-existent or has expired.
|
91
95
|
|
92
|
-
|
96
|
+
The `use_replication_endpoint` flag will append `/replication` to all resource queries if set to `true`. This is required
|
97
|
+
by some data sources to query resources beyond 10,000 records.
|
93
98
|
|
94
99
|
### Caching Metadata
|
95
100
|
|
@@ -108,9 +113,9 @@ If you don't have access to the file system, like on Heroku, or you just don't w
|
|
108
113
|
|
109
114
|
```ruby
|
110
115
|
class MyCacheStore < ResoTransport::MetadataCache
|
111
|
-
|
116
|
+
|
112
117
|
def read
|
113
|
-
# read `name` from somewhere
|
118
|
+
# read `name` from somewhere
|
114
119
|
end
|
115
120
|
|
116
121
|
def write(data)
|
@@ -158,12 +163,25 @@ Once you have a successful connection you can explore what resources are availab
|
|
158
163
|
#=> {"Property"=>#<ResoTransport::Resource entity_set="Property", schema="ODataService">, "Office"=>#<ResoTransport::Resource entity_set="Office", schema="ODataService">, "Member"=>#<ResoTransport::Resource entity_set="Member", schema="ODataService">}
|
159
164
|
|
160
165
|
@client.resources["Property"]
|
161
|
-
#=> #<ResoTransport::Resource entity_set="Property", schema="ODataService">
|
166
|
+
#=> #<ResoTransport::Resource entity_set="Property", schema="ODataService">
|
162
167
|
|
163
168
|
@client.resources["Property"].query.limit(1).results
|
164
169
|
#=> Results Array
|
165
170
|
```
|
166
171
|
|
172
|
+
If the resource contains localizations you can access those as well.
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
@client.resources["Property"].localizations
|
176
|
+
#=> {"CommercialSale"=>{"Name"=>"CommercialSale", "ResourcePath"=>"/Property?Class=CommercialSale", "Description"=>"Contains data for Commercial searches.", "DateTimeStamp"=>"2021-05-03T18:13:20.643-07:00"}, "Residential"=>{"Name"=>"Residential", "ResourcePath"=>"/Property?Class=Residential", "Description"=>"Contains data for Residential searches.", "DateTimeStamp"=>"2021-05-03T18:13:20.643-07:00"}}
|
177
|
+
```
|
178
|
+
|
179
|
+
If a resource contains localizations you must select one by name, before querying, like so:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
@client.resources["Property"].localization('Residential').query.limit(1).results
|
183
|
+
```
|
184
|
+
|
167
185
|
#### Querying
|
168
186
|
|
169
187
|
ResoTransport provides powerful querying capabilities:
|
@@ -196,7 +214,7 @@ To see what child records can be expanded look at `expandable`:
|
|
196
214
|
|
197
215
|
```ruby
|
198
216
|
@resource.expandable
|
199
|
-
#=> [#<struct ResoTransport::Property name="Media", data_type="Collection(RESO.Media)", attrs={"Name"=>"Media", "Type"=>"Collection(RESO.Media)"}, multi=true, enum=nil, complex_type=nil, entity_type=#<struct ResoTransport::EntityType name="Media", base_type=nil, primary_key="MediaKey", schema="CoreLogic.DataStandard.RESO.DD">> ...]
|
217
|
+
#=> [#<struct ResoTransport::Property name="Media", data_type="Collection(RESO.Media)", attrs={"Name"=>"Media", "Type"=>"Collection(RESO.Media)"}, multi=true, enum=nil, complex_type=nil, entity_type=#<struct ResoTransport::EntityType name="Media", base_type=nil, primary_key="MediaKey", schema="CoreLogic.DataStandard.RESO.DD">> ...]
|
200
218
|
```
|
201
219
|
|
202
220
|
Use `expand` to expand child records with the top level results.
|
@@ -210,7 +228,7 @@ You have several options to expand multiple child record sets. Each of these wil
|
|
210
228
|
|
211
229
|
```ruby
|
212
230
|
@resource.query.expand("Media", "Office").limit(10).results
|
213
|
-
|
231
|
+
|
214
232
|
@resource.query.expand(["Media", "Office"]).limit(10).results
|
215
233
|
|
216
234
|
@resource.query.expand("Media").expand("Office").limit(10).results
|
@@ -257,7 +275,7 @@ When querying for an enumeration value, you can provide either the system name,
|
|
257
275
|
|
258
276
|
```ruby
|
259
277
|
@resource.query.eq(StandardStatus: "Active Under Contract").limit(1).compile_params
|
260
|
-
#=> {"$top"=>1, "$filter"=>"StandardStatus eq 'ActiveUnderContract'"}
|
278
|
+
#=> {"$top"=>1, "$filter"=>"StandardStatus eq 'ActiveUnderContract'"}
|
261
279
|
```
|
262
280
|
|
263
281
|
## Development
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'reso_transport'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -12,19 +12,19 @@ require "reso_transport"
|
|
12
12
|
#
|
13
13
|
|
14
14
|
ResoTransport.configure do |c|
|
15
|
-
c.logger = Logger.new(
|
15
|
+
c.logger = Logger.new('log/console.log')
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
require "irb"
|
18
|
+
require 'irb'
|
20
19
|
require 'yaml'
|
21
20
|
require 'byebug'
|
22
21
|
|
23
|
-
SECRETS = YAML.load_file(
|
22
|
+
SECRETS = YAML.load_file('secrets.yml')
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
SECRETS.each do |name, data|
|
25
|
+
data[:logger] = Logger.new($stdout)
|
26
|
+
client = ResoTransport::Client.new(data)
|
27
|
+
instance_variable_set("@#{name}", client)
|
28
|
+
end
|
29
29
|
|
30
30
|
IRB.start(__FILE__)
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/lib/reso_transport.rb
CHANGED
@@ -5,41 +5,30 @@ require 'faraday'
|
|
5
5
|
require 'json'
|
6
6
|
require 'time'
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
# module Utils
|
27
|
-
|
28
|
-
# def escape(str)
|
29
|
-
# str.to_s.gsub(ESCAPE_RE) do |match|
|
30
|
-
# '%' + match.unpack('H2' * match.bytesize).join('%').upcase
|
31
|
-
# end.gsub(" ","%20")
|
32
|
-
|
33
|
-
# end
|
34
|
-
# end
|
35
|
-
# end
|
36
|
-
|
37
|
-
Faraday::Utils.default_space_encoding = "%20"
|
8
|
+
require 'reso_transport/version'
|
9
|
+
require 'reso_transport/configuration'
|
10
|
+
require 'reso_transport/authentication'
|
11
|
+
require 'reso_transport/client'
|
12
|
+
require 'reso_transport/resource'
|
13
|
+
require 'reso_transport/metadata'
|
14
|
+
require 'reso_transport/metadata_cache'
|
15
|
+
require 'reso_transport/metadata_parser'
|
16
|
+
require 'reso_transport/datasystem'
|
17
|
+
require 'reso_transport/datasystem_parser'
|
18
|
+
require 'reso_transport/schema'
|
19
|
+
require 'reso_transport/entity_set'
|
20
|
+
require 'reso_transport/entity_type'
|
21
|
+
require 'reso_transport/enum'
|
22
|
+
require 'reso_transport/property'
|
23
|
+
require 'reso_transport/query'
|
24
|
+
|
25
|
+
Faraday::Utils.default_space_encoding = '%20'
|
38
26
|
|
39
27
|
module ResoTransport
|
40
28
|
class Error < StandardError; end
|
29
|
+
|
41
30
|
class AccessDenied < StandardError; end
|
42
|
-
ODATA_TIME_FORMAT =
|
31
|
+
ODATA_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'.freeze
|
43
32
|
|
44
33
|
class << self
|
45
34
|
attr_writer :configuration
|
@@ -53,8 +42,7 @@ module ResoTransport
|
|
53
42
|
yield(configuration)
|
54
43
|
end
|
55
44
|
|
56
|
-
def self.split_schema_and_class_name(
|
57
|
-
|
45
|
+
def self.split_schema_and_class_name(text)
|
46
|
+
text.to_s.partition(/(\w+)$/).first(2).map { |s| s.sub(/\.$/, '') }
|
58
47
|
end
|
59
|
-
|
60
48
|
end
|
@@ -1,20 +1,32 @@
|
|
1
1
|
module ResoTransport
|
2
2
|
module Authentication
|
3
3
|
class FetchTokenAuth < AuthStrategy
|
4
|
-
attr_reader :
|
5
|
-
|
4
|
+
attr_reader :endpoint,
|
5
|
+
:client_id,
|
6
|
+
:client_secret,
|
7
|
+
:grant_type,
|
8
|
+
:scope,
|
9
|
+
:username,
|
10
|
+
:password
|
11
|
+
|
6
12
|
def initialize(options)
|
7
|
-
|
8
|
-
|
13
|
+
super()
|
14
|
+
|
15
|
+
@grant_type = options.fetch(:grant_type, 'client_credentials')
|
16
|
+
@scope = options.fetch(:scope, 'api')
|
9
17
|
@client_id = options.fetch(:client_id)
|
10
18
|
@client_secret = options.fetch(:client_secret)
|
11
19
|
@endpoint = options.fetch(:endpoint)
|
20
|
+
@username = options.fetch(:username, nil)
|
21
|
+
@password = options.fetch(:password, nil)
|
22
|
+
end
|
12
23
|
|
13
|
-
|
24
|
+
def connection
|
25
|
+
@connection ||= Faraday.new(@endpoint) do |faraday|
|
14
26
|
faraday.request :url_encoded
|
15
27
|
faraday.response :logger, ResoTransport.configuration.logger if ResoTransport.configuration.logger
|
16
28
|
faraday.adapter Faraday.default_adapter
|
17
|
-
faraday.basic_auth
|
29
|
+
faraday.basic_auth client_id, client_secret
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
@@ -30,19 +42,26 @@ module ResoTransport
|
|
30
42
|
Access.new({
|
31
43
|
access_token: json.fetch('access_token'),
|
32
44
|
expires_in: json.fetch('expires_in', 1 << (1.size * 8 - 2) - 1),
|
33
|
-
token_type: json.fetch('token_type',
|
45
|
+
token_type: json.fetch('token_type', 'Bearer')
|
34
46
|
})
|
35
47
|
end
|
36
48
|
|
37
49
|
private
|
38
50
|
|
39
51
|
def auth_params
|
40
|
-
{
|
41
|
-
client_id:
|
52
|
+
params = {
|
53
|
+
client_id: client_id,
|
42
54
|
client_secret: client_secret,
|
43
|
-
grant_type:
|
44
|
-
scope:
|
55
|
+
grant_type: grant_type,
|
56
|
+
scope: scope
|
45
57
|
}
|
58
|
+
|
59
|
+
if grant_type == 'password'
|
60
|
+
params[:username] = username
|
61
|
+
params[:password] = password
|
62
|
+
end
|
63
|
+
|
64
|
+
params
|
46
65
|
end
|
47
66
|
end
|
48
67
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ResoTransport
|
2
|
+
class BaseMetadata
|
3
|
+
MIME_TYPES = {
|
4
|
+
xml: 'application/xml',
|
5
|
+
json: 'application/json'
|
6
|
+
}.freeze
|
7
|
+
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
@prefix = nil
|
13
|
+
@classname = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def prefix
|
17
|
+
raise 'prefix not set' unless @prefix
|
18
|
+
|
19
|
+
@prefix
|
20
|
+
end
|
21
|
+
|
22
|
+
def classname
|
23
|
+
raise 'classname not set' unless @classname
|
24
|
+
|
25
|
+
@classname
|
26
|
+
end
|
27
|
+
|
28
|
+
def parser
|
29
|
+
@parser ||= Object::const_get("#{classname}Parser").new.parse(data)
|
30
|
+
end
|
31
|
+
|
32
|
+
def data
|
33
|
+
if cache_file
|
34
|
+
cache.read || cache.write(raw)
|
35
|
+
else
|
36
|
+
raw
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def cache
|
41
|
+
@cache ||= client.send("#{prefix}_cache").new(cache_file)
|
42
|
+
end
|
43
|
+
|
44
|
+
def cache_file
|
45
|
+
@cache_file ||= client.send "#{prefix}_file"
|
46
|
+
end
|
47
|
+
|
48
|
+
def raw
|
49
|
+
if response.success?
|
50
|
+
response.body
|
51
|
+
else
|
52
|
+
puts response.body
|
53
|
+
raise "Error getting #{classname}!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def response
|
58
|
+
raise 'Must implement response method'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,35 +1,52 @@
|
|
1
1
|
module ResoTransport
|
2
2
|
class Client
|
3
|
-
attr_reader :connection, :uid, :vendor, :endpoint, :
|
4
|
-
|
3
|
+
attr_reader :connection, :uid, :vendor, :endpoint, :authentication, :md_file, :md_cache, :ds_file, :ds_cache,
|
4
|
+
:use_replication_endpoint
|
5
|
+
|
5
6
|
def initialize(options)
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
|
14
|
-
@
|
7
|
+
@use_replication_endpoint = options.fetch(:use_replication_endpoint, false)
|
8
|
+
@endpoint = options.fetch(:endpoint)
|
9
|
+
@md_file = options.fetch(:md_file, nil)
|
10
|
+
@ds_file = options.fetch(:ds_file, nil)
|
11
|
+
@authentication = ensure_valid_auth_strategy(options.fetch(:authentication))
|
12
|
+
@vendor = options.fetch(:vendor, {})
|
13
|
+
@faraday_options = options.fetch(:faraday_options, {})
|
14
|
+
@logger = options.fetch(:logger, nil)
|
15
|
+
@md_cache = options.fetch(:md_cache, ResoTransport::MetadataCache)
|
16
|
+
@ds_cache = options.fetch(:ds_cache, ResoTransport::MetadataCache)
|
17
|
+
@connection = establish_connection
|
18
|
+
end
|
19
|
+
|
20
|
+
def establish_connection
|
21
|
+
Faraday.new(@endpoint, @faraday_options) do |faraday|
|
15
22
|
faraday.request :url_encoded
|
16
23
|
faraday.response :logger, @logger || ResoTransport.configuration.logger
|
17
|
-
#yield faraday if block_given?
|
18
24
|
faraday.use Authentication::Middleware, @authentication
|
19
|
-
faraday.adapter Faraday.default_adapter #unless faraday.builder.send(:adapter_set?)
|
25
|
+
faraday.adapter Faraday.default_adapter # unless faraday.builder.send(:adapter_set?)
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
29
|
def resources
|
24
|
-
@resources ||= metadata.entity_sets.map {|es| {es.name =>
|
30
|
+
@resources ||= metadata.entity_sets.map { |es| { es.name => resource_for(es) } }.reduce(:merge!)
|
31
|
+
end
|
32
|
+
|
33
|
+
def resource_for(entity_set)
|
34
|
+
localizations = {}
|
35
|
+
localizations = datasystem.localizations_for(entity_set.entity_type) if metadata.datasystem?
|
36
|
+
|
37
|
+
Resource.new(self, entity_set, localizations)
|
25
38
|
end
|
26
39
|
|
27
40
|
def metadata
|
28
41
|
@metadata ||= Metadata.new(self)
|
29
42
|
end
|
30
43
|
|
44
|
+
def datasystem
|
45
|
+
@datasystem ||= Datasystem.new(self)
|
46
|
+
end
|
47
|
+
|
31
48
|
def to_s
|
32
|
-
%(#<ResoTransport::Client endpoint="#{endpoint}", md_file="#{md_file}">)
|
49
|
+
%(#<ResoTransport::Client endpoint="#{endpoint}", md_file="#{md_file}", ds_file="#{ds_file}">)
|
33
50
|
end
|
34
51
|
|
35
52
|
def inspect
|
@@ -41,7 +58,7 @@ module ResoTransport
|
|
41
58
|
def ensure_valid_auth_strategy(options)
|
42
59
|
case options
|
43
60
|
when Hash
|
44
|
-
if options.
|
61
|
+
if options.key?(:endpoint)
|
45
62
|
Authentication::FetchTokenAuth.new(options)
|
46
63
|
else
|
47
64
|
Authentication::StaticTokenAuth.new(options)
|
@@ -50,6 +67,5 @@ module ResoTransport
|
|
50
67
|
raise ArgumentError, "#{options.inspect} invalid: cannot determine strategy"
|
51
68
|
end
|
52
69
|
end
|
53
|
-
|
54
70
|
end
|
55
71
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base_metadata'
|
2
|
+
|
3
|
+
module ResoTransport
|
4
|
+
class Datasystem < BaseMetadata
|
5
|
+
def initialize(client)
|
6
|
+
super client
|
7
|
+
@prefix = 'ds'
|
8
|
+
@classname = self.class.name
|
9
|
+
end
|
10
|
+
|
11
|
+
def localizations_for(resource_name)
|
12
|
+
localizations = parser.resources.dig(resource_name, 'Localizations') || []
|
13
|
+
localizations.map { |l| [l['Name'], l] }.to_h
|
14
|
+
end
|
15
|
+
|
16
|
+
def response
|
17
|
+
@response ||= client.connection.get('DataSystem') do |req|
|
18
|
+
req.headers['Accept'] = 'application/json'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ResoTransport
|
2
|
+
class DatasystemParser
|
3
|
+
def parse(doc)
|
4
|
+
begin
|
5
|
+
data = doc.is_a?(File) ? doc.read : doc
|
6
|
+
@json = JSON.parse data
|
7
|
+
rescue JSON::ParserError => e
|
8
|
+
@json = {}
|
9
|
+
puts e.message
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
# value ->
|
15
|
+
# Resources ->
|
16
|
+
# Name ->
|
17
|
+
# ResourcePath ->
|
18
|
+
# Localizations ->
|
19
|
+
# Name ->
|
20
|
+
# ResourcePath ->
|
21
|
+
|
22
|
+
def resources
|
23
|
+
@resources ||= @json['value'].map { |v| v['Resources'] }.flatten.compact.map { |r| [r['Name'], r] }.to_h
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
module ResoTransport
|
2
2
|
EntitySet = Struct.new(:name, :schema, :entity_type) do
|
3
|
-
|
4
3
|
def self.from_stream(args)
|
5
|
-
schema, entity_type = ResoTransport.split_schema_and_class_name(args[
|
4
|
+
schema, entity_type = ResoTransport.split_schema_and_class_name(args['EntityType'])
|
6
5
|
|
7
|
-
new(args[
|
6
|
+
new(args['Name'], schema, entity_type)
|
8
7
|
end
|
9
|
-
|
10
8
|
end
|
11
9
|
end
|
@@ -1,30 +1,29 @@
|
|
1
1
|
module ResoTransport
|
2
2
|
EntityType = Struct.new(:name, :base_type, :primary_key, :schema) do
|
3
|
-
|
4
3
|
def self.from_stream(args)
|
5
|
-
new(args[
|
4
|
+
new(args['Name'], args['BaseType'])
|
6
5
|
end
|
7
6
|
|
8
7
|
def parse(record)
|
9
|
-
record.each_pair do |k,v|
|
8
|
+
record.each_pair do |k, v|
|
10
9
|
next if v.nil?
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
|
11
|
+
property = property_map[k] || navigation_property_map[k]
|
12
|
+
record[k] = property.parse(v) if property
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
16
|
def parse_value(record)
|
18
|
-
record.each_pair do |k,v|
|
17
|
+
record.each_pair do |k, v|
|
19
18
|
next if v.nil?
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
|
20
|
+
property = property_map[k] || navigation_property_map[k]
|
21
|
+
record[k] = property.parse(v) if property
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
26
25
|
def property_map
|
27
|
-
@property_map ||= properties.
|
26
|
+
@property_map ||= properties.each_with_object({}) { |p, hsh| hsh[p.name] = p; }
|
28
27
|
end
|
29
28
|
|
30
29
|
def properties
|
@@ -32,7 +31,7 @@ module ResoTransport
|
|
32
31
|
end
|
33
32
|
|
34
33
|
def navigation_property_map
|
35
|
-
@navigation_property_map ||= navigation_properties.
|
34
|
+
@navigation_property_map ||= navigation_properties.each_with_object({}) { |p, hsh| hsh[p.name] = p; }
|
36
35
|
end
|
37
36
|
|
38
37
|
def navigation_properties
|
@@ -42,6 +41,5 @@ module ResoTransport
|
|
42
41
|
def enumerations
|
43
42
|
@enumerations ||= []
|
44
43
|
end
|
45
|
-
|
46
44
|
end
|
47
45
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
Metadata = Struct.new(:client) do
|
1
|
+
require_relative 'base_metadata'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module ResoTransport
|
4
|
+
class Metadata < BaseMetadata
|
5
|
+
def initialize(client)
|
6
|
+
super client
|
7
|
+
@prefix = 'md'
|
8
|
+
@classname = self.class.name
|
9
|
+
end
|
8
10
|
|
9
11
|
def entity_sets
|
10
12
|
parser.entity_sets
|
@@ -14,34 +16,14 @@ module ResoTransport
|
|
14
16
|
parser.schemas
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
+
def datasystem?
|
20
|
+
parser.datasystem?
|
19
21
|
end
|
20
22
|
|
21
|
-
def
|
22
|
-
@
|
23
|
-
end
|
24
|
-
|
25
|
-
def get_data
|
26
|
-
if client.md_file
|
27
|
-
md_cache.read || md_cache.write(raw)
|
28
|
-
else
|
29
|
-
raw
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def raw
|
34
|
-
resp = client.connection.get("$metadata") do |req|
|
23
|
+
def response
|
24
|
+
@response ||= client.connection.get('$metadata') do |req|
|
35
25
|
req.headers['Accept'] = MIME_TYPES[client.vendor.fetch(:metadata_format, :xml).to_sym]
|
36
26
|
end
|
37
|
-
|
38
|
-
if resp.success?
|
39
|
-
resp.body
|
40
|
-
else
|
41
|
-
puts resp.body
|
42
|
-
raise "Error getting metadata!"
|
43
|
-
end
|
44
27
|
end
|
45
|
-
|
46
28
|
end
|
47
29
|
end
|
@@ -7,15 +7,14 @@ module ResoTransport
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def read
|
10
|
-
if File.exist?(name)
|
11
|
-
|
12
|
-
|
10
|
+
return nil if !File.exist?(name) || File.size(name).zero?
|
11
|
+
|
12
|
+
File.new(name)
|
13
13
|
end
|
14
14
|
|
15
15
|
def write(raw)
|
16
|
-
File.open(name,
|
16
|
+
File.open(name, 'w') { |f| f.write(raw.force_encoding('UTF-8')) } if raw.length.positive?
|
17
17
|
File.new(name)
|
18
18
|
end
|
19
|
-
|
20
19
|
end
|
21
20
|
end
|
@@ -14,12 +14,14 @@ module ResoTransport
|
|
14
14
|
@current_complex_type = nil
|
15
15
|
@current_enum_type = nil
|
16
16
|
@current_member = nil
|
17
|
+
|
18
|
+
@datasystem = nil
|
17
19
|
end
|
18
20
|
|
19
21
|
def parse(doc)
|
20
22
|
REXML::Document.parse_stream(doc, self)
|
21
23
|
finalize
|
22
|
-
|
24
|
+
self
|
23
25
|
end
|
24
26
|
|
25
27
|
def finalize
|
@@ -54,55 +56,62 @@ module ResoTransport
|
|
54
56
|
|
55
57
|
def tag_start(name, args)
|
56
58
|
case name
|
57
|
-
when
|
59
|
+
when 'Schema'
|
58
60
|
@schemas << ResoTransport::Schema.from_stream(args)
|
59
|
-
when
|
61
|
+
when 'EntitySet'
|
60
62
|
@entity_sets << ResoTransport::EntitySet.from_stream(args)
|
61
|
-
when
|
63
|
+
when 'EntityType'
|
62
64
|
@current_entity_type = ResoTransport::EntityType.from_stream(args)
|
63
|
-
when
|
65
|
+
when 'ComplexType'
|
64
66
|
@current_complex_type = ResoTransport::EntityType.from_stream(args)
|
65
|
-
when
|
67
|
+
when 'PropertyRef'
|
66
68
|
@current_entity_type.primary_key = args['Name']
|
67
|
-
when
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
when 'Property'
|
70
|
+
if @current_entity_type
|
71
|
+
@current_entity_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last))
|
72
|
+
end
|
73
|
+
if @current_complex_type
|
74
|
+
@current_complex_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last))
|
75
|
+
end
|
76
|
+
when 'NavigationProperty'
|
71
77
|
@current_entity_type.navigation_properties << ResoTransport::Property.from_stream(args)
|
72
|
-
when
|
78
|
+
when 'EnumType'
|
73
79
|
@current_enum_type = ResoTransport::Enum.from_stream(args.merge(schema: @schemas.last))
|
74
|
-
when
|
80
|
+
when 'Member'
|
75
81
|
@current_member = ResoTransport::Member.from_stream(args)
|
76
|
-
when
|
82
|
+
when 'Annotation'
|
77
83
|
if @current_enum_type && @current_member
|
78
84
|
@current_member.annotation = args['String']
|
79
|
-
|
80
|
-
|
81
|
-
#raise args.inspect
|
82
|
-
end
|
85
|
+
elsif @current_entity_type || @current_complex_type
|
86
|
+
# raise args.inspect
|
83
87
|
end
|
84
88
|
end
|
85
|
-
rescue => e
|
89
|
+
rescue StandardError => e
|
86
90
|
puts e.inspect
|
87
91
|
puts "Error processing Tag: #{[name, args].inspect}"
|
88
92
|
end
|
89
93
|
|
90
94
|
def tag_end(name)
|
91
95
|
case name
|
92
|
-
when
|
96
|
+
when 'EntityType'
|
93
97
|
@current_entity_type.schema = @schemas.last.namespace
|
94
98
|
@schemas.last.entity_types << @current_entity_type
|
95
|
-
when
|
99
|
+
when 'ComplexType'
|
96
100
|
@current_complex_type.schema = @schemas.last.namespace
|
97
101
|
@schemas.last.complex_types << @current_complex_type
|
98
|
-
when
|
102
|
+
when 'EnumType'
|
99
103
|
@enumerations << @current_enum_type
|
100
104
|
@current_enum_type = nil
|
101
|
-
when
|
105
|
+
when 'Member'
|
102
106
|
@current_enum_type.members << @current_member
|
103
107
|
@current_member = nil
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
111
|
+
def datasystem?
|
112
|
+
return @datasystem unless @datasystem.nil?
|
113
|
+
|
114
|
+
@datasystem = @schemas.any? { |s| s.entity_types.any? { |t| t.name == 'DataSystem' } }
|
115
|
+
end
|
107
116
|
end
|
108
117
|
end
|
data/lib/reso_transport/query.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
module ResoTransport
|
2
2
|
Query = Struct.new(:resource) do
|
3
|
-
|
4
|
-
def all(*contexts, &block)
|
3
|
+
def all(*_contexts, &block)
|
5
4
|
new_query_context('and')
|
6
5
|
instance_eval(&block)
|
7
6
|
clear_query_context
|
8
|
-
|
7
|
+
self
|
9
8
|
end
|
10
9
|
|
11
10
|
def any(&block)
|
12
11
|
new_query_context('or')
|
13
12
|
instance_eval(&block)
|
14
13
|
clear_query_context
|
15
|
-
|
14
|
+
self
|
16
15
|
end
|
17
16
|
|
18
|
-
[
|
17
|
+
%i[eq ne gt ge lt le].each do |op|
|
19
18
|
define_method(op) do |conditions|
|
20
|
-
conditions.each_pair do |k,v|
|
19
|
+
conditions.each_pair do |k, v|
|
21
20
|
current_query_context << "#{k} #{op} #{encode_value(k, v)}"
|
22
21
|
end
|
23
22
|
return self
|
@@ -26,36 +25,36 @@ module ResoTransport
|
|
26
25
|
|
27
26
|
def limit(size)
|
28
27
|
options[:top] = size
|
29
|
-
|
28
|
+
self
|
30
29
|
end
|
31
30
|
|
32
31
|
def offset(size)
|
33
32
|
options[:skip] = size
|
34
|
-
|
33
|
+
self
|
35
34
|
end
|
36
35
|
|
37
|
-
def order(field, dir=nil)
|
38
|
-
options[:orderby] = [field, dir].join(
|
39
|
-
|
36
|
+
def order(field, dir = nil)
|
37
|
+
options[:orderby] = [field, dir].join(' ').strip
|
38
|
+
self
|
40
39
|
end
|
41
40
|
|
42
41
|
def include_count
|
43
42
|
options[:count] = true
|
44
|
-
|
43
|
+
self
|
45
44
|
end
|
46
45
|
|
47
46
|
def select(*fields)
|
48
|
-
os = options.fetch(:select,
|
49
|
-
options[:select] = (os + Array(fields)).uniq.join(
|
47
|
+
os = options.fetch(:select, '').split(',')
|
48
|
+
options[:select] = (os + Array(fields)).uniq.join(',')
|
50
49
|
|
51
|
-
|
50
|
+
self
|
52
51
|
end
|
53
52
|
|
54
53
|
def expand(*names)
|
55
|
-
ex = options.fetch(:expand,
|
56
|
-
options[:expand] = (ex + Array(names)).uniq.join(
|
54
|
+
ex = options.fetch(:expand, '').split(',')
|
55
|
+
options[:expand] = (ex + Array(names)).uniq.join(',')
|
57
56
|
|
58
|
-
|
57
|
+
self
|
59
58
|
end
|
60
59
|
|
61
60
|
def count
|
@@ -63,7 +62,7 @@ module ResoTransport
|
|
63
62
|
limit(1).include_count
|
64
63
|
resp = resource.get(compile_params)
|
65
64
|
parsed_body = JSON.parse(resp.body)
|
66
|
-
parsed_body.fetch(
|
65
|
+
parsed_body.fetch('@odata.count', 0)
|
67
66
|
end
|
68
67
|
|
69
68
|
def results
|
@@ -72,21 +71,28 @@ module ResoTransport
|
|
72
71
|
if resp[:success]
|
73
72
|
resp[:results]
|
74
73
|
else
|
75
|
-
puts resp
|
76
|
-
raise
|
74
|
+
puts resp[:meta]
|
75
|
+
raise 'Request Failed'
|
77
76
|
end
|
78
77
|
end
|
79
78
|
|
80
79
|
def execute
|
81
80
|
resp = resource.get(compile_params)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
81
|
+
if resp.success?
|
82
|
+
parsed_body = JSON.parse(resp.body)
|
83
|
+
results = Array(parsed_body.delete('value'))
|
84
|
+
|
85
|
+
{
|
86
|
+
success: resp.success? && !parsed_body.key?('error'),
|
87
|
+
meta: parsed_body,
|
88
|
+
results: resource.parse(results)
|
89
|
+
}
|
90
|
+
else
|
91
|
+
{
|
92
|
+
success: false,
|
93
|
+
meta: resp.body
|
94
|
+
}
|
95
|
+
end
|
90
96
|
end
|
91
97
|
|
92
98
|
def new_query_context(context)
|
@@ -110,7 +116,7 @@ module ResoTransport
|
|
110
116
|
end
|
111
117
|
|
112
118
|
def sub_queries
|
113
|
-
@sub_queries ||= Hash.new {|h,k| h[k] = { context: 'and', criteria: [] } }
|
119
|
+
@sub_queries ||= Hash.new { |h, k| h[k] = { context: 'and', criteria: [] } }
|
114
120
|
end
|
115
121
|
|
116
122
|
def compile_filters
|
@@ -120,36 +126,32 @@ module ResoTransport
|
|
120
126
|
|
121
127
|
filter_chunks = []
|
122
128
|
|
123
|
-
if global && global[:criteria]&.any?
|
124
|
-
filter_chunks << global[:criteria].join(" #{global[:context]} ")
|
125
|
-
end
|
129
|
+
filter_chunks << global[:criteria].join(" #{global[:context]} ") if global && global[:criteria]&.any?
|
126
130
|
|
127
131
|
filter_chunks << filter_groups.map do |g|
|
128
132
|
"(#{g[:criteria].join(" #{g[:context]} ")})"
|
129
|
-
end.join(
|
133
|
+
end.join(' and ')
|
130
134
|
|
131
|
-
filter_chunks.reject {|c| c ==
|
135
|
+
filter_chunks.reject { |c| c == '' }.join(' and ')
|
132
136
|
end
|
133
137
|
|
134
138
|
def compile_params
|
135
139
|
params = {}
|
136
140
|
|
137
|
-
options.each_pair do |k,v|
|
141
|
+
options.each_pair do |k, v|
|
138
142
|
params["$#{k}"] = v
|
139
143
|
end
|
140
144
|
|
141
|
-
|
142
|
-
params["$filter"] = compile_filters
|
143
|
-
end
|
145
|
+
params['$filter'] = compile_filters unless sub_queries.empty?
|
144
146
|
|
145
147
|
params
|
146
148
|
end
|
147
149
|
|
148
|
-
def encode_value(key,
|
150
|
+
def encode_value(key, val)
|
149
151
|
field = resource.property(key.to_s)
|
150
152
|
raise "Couldn't find property #{key} for #{resource.name}" if field.nil?
|
151
|
-
field.encode(v)
|
152
|
-
end
|
153
153
|
|
154
|
+
field.encode(val)
|
155
|
+
end
|
154
156
|
end
|
155
157
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ResoTransport
|
2
|
-
Resource = Struct.new(:client, :entity_set) do
|
3
|
-
|
2
|
+
Resource = Struct.new(:client, :entity_set, :localizations, :local) do
|
4
3
|
def query
|
5
4
|
Query.new(self)
|
6
5
|
end
|
@@ -10,7 +9,7 @@ module ResoTransport
|
|
10
9
|
end
|
11
10
|
|
12
11
|
def property(name)
|
13
|
-
properties.detect {|p| p.name == name }
|
12
|
+
properties.detect { |p| p.name == name }
|
14
13
|
end
|
15
14
|
|
16
15
|
def properties
|
@@ -20,13 +19,13 @@ module ResoTransport
|
|
20
19
|
def expandable
|
21
20
|
entity_type.navigation_properties
|
22
21
|
end
|
23
|
-
|
22
|
+
|
24
23
|
def entity_type
|
25
|
-
@entity_type ||= schema.entity_types.detect {|et| et.name == entity_set.entity_type }
|
24
|
+
@entity_type ||= schema.entity_types.detect { |et| et.name == entity_set.entity_type }
|
26
25
|
end
|
27
26
|
|
28
27
|
def schema
|
29
|
-
@schema ||= md.schemas.detect {|s| s.namespace == entity_set.schema }
|
28
|
+
@schema ||= md.schemas.detect { |s| s.namespace == entity_set.schema }
|
30
29
|
end
|
31
30
|
|
32
31
|
def md
|
@@ -34,15 +33,30 @@ module ResoTransport
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def parse(results)
|
37
|
-
results.map {|r| entity_type.parse(r) }
|
36
|
+
results.map { |r| entity_type.parse(r) }
|
38
37
|
end
|
39
38
|
|
40
39
|
def get(params)
|
41
|
-
client.connection.get(
|
40
|
+
client.connection.get(url, params) do |req|
|
42
41
|
req.headers['Accept'] = 'application/json'
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
45
|
+
def url
|
46
|
+
return local['ResourcePath'].gsub(%r{^/}, '') if local
|
47
|
+
|
48
|
+
raise 'Localization required' if localizations.any? && local.nil?
|
49
|
+
|
50
|
+
return "#{name}/replication" if client.use_replication_endpoint
|
51
|
+
|
52
|
+
name
|
53
|
+
end
|
54
|
+
|
55
|
+
def localization(name)
|
56
|
+
self.local = localizations[name] if localizations.key?(name)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
46
60
|
def to_s
|
47
61
|
%(#<ResoTransport::Resource entity_set="#{name}", schema="#{schema&.namespace}">)
|
48
62
|
end
|
@@ -50,6 +64,5 @@ module ResoTransport
|
|
50
64
|
def inspect
|
51
65
|
to_s
|
52
66
|
end
|
53
|
-
|
54
67
|
end
|
55
68
|
end
|
data/reso_transport.gemspec
CHANGED
@@ -1,35 +1,35 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'reso_transport/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'reso_transport'
|
8
7
|
spec.version = ResoTransport::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Jon Druse']
|
9
|
+
spec.email = ['jon@wrstudios.com']
|
11
10
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
11
|
+
spec.summary = 'A utility for consuming RESO Web API connections'
|
12
|
+
spec.description = 'Supports Trestle, Spark, Bridge Interactive, MLS Grid'
|
13
|
+
spec.homepage = 'http://github.com/wrstudios/reso_transport'
|
14
|
+
spec.license = 'MIT'
|
16
15
|
|
16
|
+
spec.required_ruby_version = '>= 2.6'
|
17
17
|
|
18
18
|
# Specify which files should be added to the gem when it is released.
|
19
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
-
spec.files
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
21
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
22
|
end
|
23
|
-
spec.bindir =
|
23
|
+
spec.bindir = 'exe'
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
-
spec.require_paths = [
|
25
|
+
spec.require_paths = ['lib']
|
26
26
|
|
27
|
-
spec.add_dependency
|
27
|
+
spec.add_dependency 'faraday', '~> 1.0.1'
|
28
28
|
|
29
|
-
spec.add_development_dependency
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency
|
34
|
-
spec.add_development_dependency
|
29
|
+
spec.add_development_dependency 'bundler', '~> 2'
|
30
|
+
spec.add_development_dependency 'byebug', '~> 11'
|
31
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
32
|
+
spec.add_development_dependency 'minitest-rg', '~> 5.0'
|
33
|
+
spec.add_development_dependency 'rake', '~> 13'
|
34
|
+
spec.add_development_dependency 'vcr', '~> 6.0'
|
35
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reso_transport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Druse
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -39,19 +39,19 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: byebug
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '11'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '11'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,33 +81,33 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '5.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '13'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '13'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: vcr
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '6.0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '6.0'
|
111
111
|
description: Supports Trestle, Spark, Bridge Interactive, MLS Grid
|
112
112
|
email:
|
113
113
|
- jon@wrstudios.com
|
@@ -116,6 +116,8 @@ extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
118
|
- ".gitignore"
|
119
|
+
- ".gitpod.yml"
|
120
|
+
- ".rubocop.yml"
|
119
121
|
- ".ruby-version"
|
120
122
|
- ".travis.yml"
|
121
123
|
- CODE_OF_CONDUCT.md
|
@@ -125,6 +127,7 @@ files:
|
|
125
127
|
- README.md
|
126
128
|
- Rakefile
|
127
129
|
- bin/console
|
130
|
+
- bin/rake
|
128
131
|
- bin/setup
|
129
132
|
- lib/reso_transport.rb
|
130
133
|
- lib/reso_transport/authentication.rb
|
@@ -133,8 +136,11 @@ files:
|
|
133
136
|
- lib/reso_transport/authentication/fetch_token_auth.rb
|
134
137
|
- lib/reso_transport/authentication/middleware.rb
|
135
138
|
- lib/reso_transport/authentication/static_token_auth.rb
|
139
|
+
- lib/reso_transport/base_metadata.rb
|
136
140
|
- lib/reso_transport/client.rb
|
137
141
|
- lib/reso_transport/configuration.rb
|
142
|
+
- lib/reso_transport/datasystem.rb
|
143
|
+
- lib/reso_transport/datasystem_parser.rb
|
138
144
|
- lib/reso_transport/entity_set.rb
|
139
145
|
- lib/reso_transport/entity_type.rb
|
140
146
|
- lib/reso_transport/enum.rb
|
@@ -160,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
160
166
|
requirements:
|
161
167
|
- - ">="
|
162
168
|
- !ruby/object:Gem::Version
|
163
|
-
version: '
|
169
|
+
version: '2.6'
|
164
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
171
|
requirements:
|
166
172
|
- - ">="
|