reso_api 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/README.md +219 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/reso_api.rb +9 -0
- data/lib/reso_api/app/models/reso.rb +2 -0
- data/lib/reso_api/app/models/reso/api.rb +2 -0
- data/lib/reso_api/app/models/reso/api/client.rb +141 -0
- data/lib/reso_api/config/inflections.rb +4 -0
- data/lib/reso_api/version.rb +3 -0
- data/reso_api.gemspec +27 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d953ced633c6228fbb7dd33b4698d499121580a3d7f44b077d7571c6694adcc6
|
4
|
+
data.tar.gz: 3301e9b25719782a3c3ccd4a665668c0cec274edb540a8d8b679ed3930148afc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 107d644298494ff5d5cc3145713ff23ca8b442c296db4611a2502943600eb858b972fd83263743575923cbb96e09f2d871c25bc2cbc5ca78a901dc832a113d9e
|
7
|
+
data.tar.gz: ca3d8603f3e3d259169a94da52308c3ea3aa3df6d6c429cc30eeb82f5bd6a972dc86743b19465a9fbbd719f349bac40321fab6694642b92b6fecfaa46ccde5c3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
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 medlund@mac.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
ADDED
data/README.md
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
# RESO API
|
2
|
+
|
3
|
+
Ruby wrapper for easy interaction with a RESO Web API compliant server.
|
4
|
+
|
5
|
+
This document does not documentation for the RESO Web API. More information about the RESO Web API standard can be found on [RESO][]'s website.
|
6
|
+
|
7
|
+
[RESO]: https://www.reso.org/reso-web-api/
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'reso_api'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install reso_api
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Authentication and Access
|
28
|
+
|
29
|
+
To set up an API client and access a service, you need three pieces of information:
|
30
|
+
|
31
|
+
- Client ID
|
32
|
+
- Client Secret
|
33
|
+
- Base API endpoint
|
34
|
+
|
35
|
+
You pass these three pieces of information when creating an instance of an API client:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
client = RESO::API::Client.new(client_id: client_id, client_secret: client_secret, base_url: base_url)
|
39
|
+
```
|
40
|
+
|
41
|
+
When calling API endpoints using the initialized client, it will automatically fetch and manage access and authentication tokens transparently in the background.
|
42
|
+
|
43
|
+
### Resources
|
44
|
+
|
45
|
+
#### Supported
|
46
|
+
|
47
|
+
- Property
|
48
|
+
|
49
|
+
#### Planned
|
50
|
+
|
51
|
+
- Media
|
52
|
+
- Member
|
53
|
+
- Office
|
54
|
+
|
55
|
+
### Retrieving Metadata
|
56
|
+
|
57
|
+
You can fetch metadata for supported resources:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
client.metadata
|
61
|
+
```
|
62
|
+
|
63
|
+
The response will be an EDMX xml schema document that matches the [RESO Data Dictionary standard][].
|
64
|
+
|
65
|
+
[RESO Data Dictionary standard]: https://www.reso.org/data-dictionary/
|
66
|
+
|
67
|
+
### Listing Requests
|
68
|
+
|
69
|
+
The simplest query is simply to call `properties` on the initialized client:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
client.properties
|
73
|
+
```
|
74
|
+
|
75
|
+
The API will return a JSON response with an array of listing JSON objects.
|
76
|
+
|
77
|
+
### Getting a single listing
|
78
|
+
|
79
|
+
You can look up a single listing by sending a query with the listing's unique id (ListingKey).
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
client.property('3yd-BINDER-5508272')
|
83
|
+
```
|
84
|
+
|
85
|
+
The response will be a single listing JSON object.
|
86
|
+
|
87
|
+
### Running queries
|
88
|
+
|
89
|
+
#### $filter
|
90
|
+
|
91
|
+
You can use `$filter` to send simple and complex queries to get a subset of listings depending on your particular use case.
|
92
|
+
|
93
|
+
To use `$filter`, pass it an expression in the format `FieldName operator Value`. For example, this query will return listings where the `StandardStatus` field equals (`eq`) the value `'Active'`:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
client.properties(filter: "StandardStatus eq 'Active'")
|
97
|
+
```
|
98
|
+
|
99
|
+
You can combine expressions together with or and and to perform more complex queries.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
client.properties(filter: "StandardStatus eq 'Active' and BrokerName eq 'Doe Brokerage'")
|
103
|
+
```
|
104
|
+
RESO Web API is built on the OData standard, but only requires compliant servers to support a subset of queries:
|
105
|
+
|
106
|
+
| Operator | Description | Example |
|
107
|
+
|------------|------------------------|------------------------------|
|
108
|
+
| `eq` | Equals | `StandardStatus eq 'Active'` |
|
109
|
+
| `ne` | Not equals | `StandardStatus ne 'Active'` |
|
110
|
+
| `ge` | Greater than or equals | `ListPrice ge 100000` |
|
111
|
+
| `gt` | Greater than | `ListPrice gt 100000` |
|
112
|
+
| `le` | Less than or equals | `ListPrice le 100000` |
|
113
|
+
| `lt` | Less than | `ListPrice lt 100000` |
|
114
|
+
|
115
|
+
#### $select
|
116
|
+
|
117
|
+
Instead of returning all of the listing fields in the response, you can use `$select` to only return specific fields you need.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
client.properties(select: "ListingKey")
|
121
|
+
client.properties(select: "ListingKey", filter: "StandardStatus eq 'Active'")
|
122
|
+
```
|
123
|
+
|
124
|
+
You can specify multiple fields to return by adding a "," between the fields in the `$select` parameter:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
client.properties(select: "ListingKey,StandardStatus")
|
128
|
+
```
|
129
|
+
|
130
|
+
#### $orderby
|
131
|
+
|
132
|
+
You can order the results by a field using `$orderby`:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
client.properties(orderby: "City desc")
|
136
|
+
```
|
137
|
+
|
138
|
+
#### Pagination, $top, and $skip
|
139
|
+
|
140
|
+
The default number of results returned is 100. You can override the default limit using the `$top` parameter. The higher the number specific for `$top`, the longer the API response will take, and pay attention to that different services does enforce a cap for number of records returned.
|
141
|
+
|
142
|
+
You can paginate through multiple sets of results using `$skip`, this can help you process multiple records quickly. In addition, if you use `$select` to target only certain fields, the API response time will be faster.
|
143
|
+
|
144
|
+
The following example API request will get the next 200 records starting at the 500th record:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
client.properties(select: "ListingKey", top: 200, skip: 500)
|
148
|
+
```
|
149
|
+
|
150
|
+
As you paginate through very large datasets, you might notice that the higher you set `$skip` the longer it takes for the API to return results. For those use cases, you should use `$skiptoken` to process very large datasets quickly.
|
151
|
+
|
152
|
+
#### Using $skiptoken for large datasets
|
153
|
+
|
154
|
+
`$skiptoken` can be used in combination with `$orderby` to process large datasets. To illustrate `$skiptoken`, we will use the following request to get 5 records ordered by `ListingKey`:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
client.properties(top: 5, orderby: "ListingKey")
|
158
|
+
```
|
159
|
+
|
160
|
+
An extract of the result could be:
|
161
|
+
|
162
|
+
```
|
163
|
+
{
|
164
|
+
"@odata.context": "http://some.server.com/odata/$metadata#Property(ListingKey)",
|
165
|
+
"value": [
|
166
|
+
{
|
167
|
+
"ListingKey": "3yd-AAABORMI-2813483"
|
168
|
+
},
|
169
|
+
{
|
170
|
+
"ListingKey": "3yd-AAABORMI-2910696"
|
171
|
+
},
|
172
|
+
{
|
173
|
+
"ListingKey": "3yd-AAABORMI-3101621"
|
174
|
+
},
|
175
|
+
{
|
176
|
+
"ListingKey": "3yd-AAABORMI-3101967"
|
177
|
+
},
|
178
|
+
{
|
179
|
+
"ListingKey": "3yd-AAABORMI-3200394"
|
180
|
+
}
|
181
|
+
]
|
182
|
+
}
|
183
|
+
```
|
184
|
+
|
185
|
+
To get the next set of records, you would then use the value of the ListingKey field for the last record in the current set (3yd-AAABORMI-3200394) as your value for `$skiptoken`:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
client.properties(top: 5, orderby: "ListingKey", skiptoken: "3yd-AAABORMI-3200394")
|
189
|
+
```
|
190
|
+
|
191
|
+
`$skiptoken` allows you to process large datasets from the API in a sequence without sacrificing performance. The drawback is that you cannot "skip" to a random page, for that you must use the regular `$skip` parameter.
|
192
|
+
|
193
|
+
## Compatibility
|
194
|
+
|
195
|
+
This gem should work with any RESO Web API compliant service, but these are those that have been confirmed to work.
|
196
|
+
|
197
|
+
- [ListHub](https://www.listhub.com)
|
198
|
+
|
199
|
+
If you use this gem to connect to another service or MLS, please submit a pull request with that service added in alphabetical order in this list.
|
200
|
+
|
201
|
+
## Acknowledgment
|
202
|
+
|
203
|
+
The inspiration for this gem and the outline and examples in this README is based on the [ListHub API][].
|
204
|
+
|
205
|
+
[ListHub API]: https://developer.listhub.com/api/
|
206
|
+
|
207
|
+
## Development
|
208
|
+
|
209
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
210
|
+
|
211
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
212
|
+
|
213
|
+
## Contributing
|
214
|
+
|
215
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/arcticleo/reso_api. 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.
|
216
|
+
|
217
|
+
## Code of Conduct
|
218
|
+
|
219
|
+
Everyone interacting in the RESO API project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/arcticleo/reso_api/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "reso_api"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/reso_api.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require "reso_api/version"
|
2
|
+
# require "reso_api/railtie" if defined?(Rails)
|
3
|
+
require "reso_api/config/inflections.rb"
|
4
|
+
require "reso_api/app/models/reso.rb"
|
5
|
+
require "reso_api/app/models/reso/api.rb"
|
6
|
+
require "reso_api/app/models/reso/api/client.rb"
|
7
|
+
|
8
|
+
module ResoApi
|
9
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module RESO
|
2
|
+
module API
|
3
|
+
class Client
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'oauth2'
|
7
|
+
require 'json'
|
8
|
+
require 'tmpdir'
|
9
|
+
|
10
|
+
attr_accessor :client_id, :client_secret, :base_url
|
11
|
+
|
12
|
+
def initialize(**opts)
|
13
|
+
@client_id, @client_secret, @base_url = opts.values_at(:client_id, :client_secret, :base_url)
|
14
|
+
validate!
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate!
|
18
|
+
raise 'Missing Client ID `client_id`' if client_id.nil?
|
19
|
+
raise 'Missing Client Secret `client_secret`' if client_secret.nil?
|
20
|
+
raise 'Missing API Base URL `base_url`' if base_url.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
RESOURCE_KEYS = {
|
24
|
+
media: "MediaKey",
|
25
|
+
members: "MemberKey",
|
26
|
+
offices: "OfficeKey",
|
27
|
+
properties: "ListingKey"
|
28
|
+
}
|
29
|
+
|
30
|
+
DETAIL_ENDPOINTS = {
|
31
|
+
medium: "odata/Media",
|
32
|
+
member: "odata/Member",
|
33
|
+
office: "odata/Office",
|
34
|
+
property: "odata/Property"
|
35
|
+
}
|
36
|
+
|
37
|
+
FILTERABLE_ENDPOINTS = {
|
38
|
+
media: "odata/Media",
|
39
|
+
members: "odata/Member",
|
40
|
+
offices: "odata/Office",
|
41
|
+
properties: "odata/Property"
|
42
|
+
}
|
43
|
+
|
44
|
+
PASSTHROUGH_ENDPOINTS = {
|
45
|
+
metadata: "odata/$metadata"
|
46
|
+
}
|
47
|
+
|
48
|
+
FILTERABLE_ENDPOINTS.keys.each do |method_name|
|
49
|
+
define_method method_name do |*args|
|
50
|
+
hash = args.first.is_a?(Hash) ? args.first : {}
|
51
|
+
endpoint = FILTERABLE_ENDPOINTS[method_name]
|
52
|
+
params = {
|
53
|
+
"$select": hash[:select],
|
54
|
+
"$filter": hash[:filter],
|
55
|
+
"$top": hash[:top] ||= 100,
|
56
|
+
"$skip": hash[:skip] ||= 0,
|
57
|
+
"$orderby": hash[:orderby] ||= RESOURCE_KEYS[method_name],
|
58
|
+
"$skiptoken": hash[:skiptoken],
|
59
|
+
"$expand": hash[:expand],
|
60
|
+
"$count": hash[:count].to_s.presence
|
61
|
+
}.compact
|
62
|
+
return perform_call(endpoint, params)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
DETAIL_ENDPOINTS.keys.each do |method_name|
|
67
|
+
define_method method_name do |*args|
|
68
|
+
endpoint = "#{DETAIL_ENDPOINTS[method_name]}('#{args.try(:first)}')"
|
69
|
+
perform_call(endpoint, nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
PASSTHROUGH_ENDPOINTS.keys.each do |method_name|
|
74
|
+
define_method method_name do |*args|
|
75
|
+
endpoint = PASSTHROUGH_ENDPOINTS[method_name]
|
76
|
+
perform_call(endpoint, nil)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def oauth2_client
|
81
|
+
OAuth2::Client.new(
|
82
|
+
client_id,
|
83
|
+
client_secret,
|
84
|
+
token_url: [base_url, "oauth2/token"].join
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def oauth2_token
|
89
|
+
payload = oauth2_payload
|
90
|
+
token = JWT.decode(payload.token, nil, false)
|
91
|
+
exp_timestamp = Hash(token.try(:first))["exp"].to_s
|
92
|
+
expiration = DateTime.strptime(exp_timestamp, '%s').utc rescue DateTime.now.utc
|
93
|
+
if expiration > DateTime.now.utc
|
94
|
+
return payload.token
|
95
|
+
else
|
96
|
+
@oauth2_payload = oauth2_client.client_credentials.get_token
|
97
|
+
File.write(oauth2_token_path, @oauth2_payload.to_hash.to_json)
|
98
|
+
return @oauth2_payload.token
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def oauth2_token_path
|
103
|
+
File.join(Dir.tmpdir, [base_url.parameterize, "-oauth-token.json"].join)
|
104
|
+
end
|
105
|
+
|
106
|
+
def oauth2_payload
|
107
|
+
@oauth2_payload ||= get_oauth2_payload
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_oauth2_payload
|
111
|
+
if File.exist?(oauth2_token_path)
|
112
|
+
persisted = File.read(oauth2_token_path)
|
113
|
+
payload = OAuth2::AccessToken.from_hash(oauth2_client, JSON.parse(persisted))
|
114
|
+
else
|
115
|
+
payload = oauth2_client.client_credentials.get_token
|
116
|
+
File.write(oauth2_token_path, payload.to_hash.to_json)
|
117
|
+
end
|
118
|
+
return payload
|
119
|
+
end
|
120
|
+
|
121
|
+
def uri_for_endpoint endpoint
|
122
|
+
return URI([base_url, endpoint].join)
|
123
|
+
end
|
124
|
+
|
125
|
+
def perform_call(endpoint, params)
|
126
|
+
uri = uri_for_endpoint(endpoint)
|
127
|
+
if params.present?
|
128
|
+
query = params.present? ? URI.encode_www_form(params).gsub("+", " ") : ""
|
129
|
+
uri.query && uri.query.length > 0 ? uri.query += '&' + query : uri.query = query
|
130
|
+
end
|
131
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
132
|
+
request['Authorization'] = "Bearer #{oauth2_token}"
|
133
|
+
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
134
|
+
http.request(request)
|
135
|
+
end
|
136
|
+
return JSON(response.body) rescue response.body
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/reso_api.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "reso_api/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "reso_api"
|
8
|
+
spec.version = ResoApi::VERSION
|
9
|
+
spec.authors = ["Michael Edlund"]
|
10
|
+
spec.email = ["medlund@mac.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{RESO Web API Wrapper}
|
13
|
+
spec.description = %q{Ruby wrapper for easy interaction with a RESO Web API compliant server.}
|
14
|
+
spec.homepage = "https://github.com/arcticleo/reso_api"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
spec.add_dependency "oauth2"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reso_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Edlund
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-05-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: oauth2
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Ruby wrapper for easy interaction with a RESO Web API compliant server.
|
70
|
+
email:
|
71
|
+
- medlund@mac.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".travis.yml"
|
79
|
+
- CODE_OF_CONDUCT.md
|
80
|
+
- Gemfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/console
|
84
|
+
- bin/setup
|
85
|
+
- lib/reso_api.rb
|
86
|
+
- lib/reso_api/app/models/reso.rb
|
87
|
+
- lib/reso_api/app/models/reso/api.rb
|
88
|
+
- lib/reso_api/app/models/reso/api/client.rb
|
89
|
+
- lib/reso_api/config/inflections.rb
|
90
|
+
- lib/reso_api/version.rb
|
91
|
+
- reso_api.gemspec
|
92
|
+
homepage: https://github.com/arcticleo/reso_api
|
93
|
+
licenses: []
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.7.6
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: RESO Web API Wrapper
|
115
|
+
test_files: []
|