rets-hack 0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +142 -0
  3. data/Manifest.txt +58 -0
  4. data/README.md +129 -0
  5. data/Rakefile +28 -0
  6. data/bin/rets +202 -0
  7. data/example/connect.rb +19 -0
  8. data/example/get-photos.rb +20 -0
  9. data/example/get-property.rb +16 -0
  10. data/lib/rets/client.rb +373 -0
  11. data/lib/rets/client_progress_reporter.rb +48 -0
  12. data/lib/rets/http_client.rb +133 -0
  13. data/lib/rets/locking_http_client.rb +34 -0
  14. data/lib/rets/measuring_http_client.rb +27 -0
  15. data/lib/rets/metadata/caching.rb +59 -0
  16. data/lib/rets/metadata/containers.rb +89 -0
  17. data/lib/rets/metadata/file_cache.rb +29 -0
  18. data/lib/rets/metadata/json_serializer.rb +27 -0
  19. data/lib/rets/metadata/lookup_table.rb +65 -0
  20. data/lib/rets/metadata/lookup_type.rb +19 -0
  21. data/lib/rets/metadata/marshal_serializer.rb +27 -0
  22. data/lib/rets/metadata/multi_lookup_table.rb +70 -0
  23. data/lib/rets/metadata/null_cache.rb +24 -0
  24. data/lib/rets/metadata/resource.rb +103 -0
  25. data/lib/rets/metadata/rets_class.rb +57 -0
  26. data/lib/rets/metadata/rets_object.rb +41 -0
  27. data/lib/rets/metadata/root.rb +155 -0
  28. data/lib/rets/metadata/table.rb +33 -0
  29. data/lib/rets/metadata/table_factory.rb +19 -0
  30. data/lib/rets/metadata/yaml_serializer.rb +27 -0
  31. data/lib/rets/metadata.rb +18 -0
  32. data/lib/rets/parser/compact.rb +117 -0
  33. data/lib/rets/parser/error_checker.rb +56 -0
  34. data/lib/rets/parser/multipart.rb +39 -0
  35. data/lib/rets.rb +269 -0
  36. data/test/fixtures.rb +324 -0
  37. data/test/helper.rb +14 -0
  38. data/test/test_caching.rb +89 -0
  39. data/test/test_client.rb +307 -0
  40. data/test/test_error_checker.rb +87 -0
  41. data/test/test_file_cache.rb +42 -0
  42. data/test/test_http_client.rb +132 -0
  43. data/test/test_json_serializer.rb +26 -0
  44. data/test/test_locking_http_client.rb +29 -0
  45. data/test/test_marshal_serializer.rb +26 -0
  46. data/test/test_metadata.rb +71 -0
  47. data/test/test_metadata_class.rb +50 -0
  48. data/test/test_metadata_lookup_table.rb +21 -0
  49. data/test/test_metadata_lookup_type.rb +21 -0
  50. data/test/test_metadata_multi_lookup_table.rb +60 -0
  51. data/test/test_metadata_object.rb +33 -0
  52. data/test/test_metadata_resource.rb +148 -0
  53. data/test/test_metadata_root.rb +151 -0
  54. data/test/test_metadata_table.rb +21 -0
  55. data/test/test_metadata_table_factory.rb +24 -0
  56. data/test/test_parser_compact.rb +115 -0
  57. data/test/test_parser_multipart.rb +39 -0
  58. data/test/test_yaml_serializer.rb +26 -0
  59. data/test/vcr_cassettes/unauthorized_response.yml +262 -0
  60. metadata +227 -0
@@ -0,0 +1,115 @@
1
+ require_relative "helper"
2
+
3
+ class TestParserCompact < MiniTest::Test
4
+ def test_parse_document_raises_on_invalid_delimiter
5
+ assert_raises Rets::Parser::Compact::InvalidDelimiter do
6
+ Rets::Parser::Compact.parse_document(INVALID_DELIMETER)
7
+ end
8
+ end
9
+
10
+ def test_parse_document_delegates_to_parse
11
+ result = Rets::Parser::Compact.parse_document(COMPACT)
12
+
13
+ assert_equal([{"A" => "1", "B" => "2"}, {"A" => "4", "B" => "5"}], result)
14
+ end
15
+
16
+ def test_parser_rejects_empty_key_value_pairs
17
+ result = Rets::Parser::Compact.parse_document(METADATA_OBJECT)
18
+
19
+ result.each do |row|
20
+ assert !row.any? { |k,v| k.to_s.size == 0 }, "Should not contain empty keys"
21
+ end
22
+ end
23
+
24
+ # RMLS does this. :|
25
+ def test_remaining_columns_produce_empty_string_values
26
+ column_names = "A B C D"
27
+ data = "1 2"
28
+
29
+ assert_equal({"A" => "1", "B" => "2", "C" => "", "D" => ""}, Rets::Parser::Compact.parse(column_names, data, ' '))
30
+ end
31
+
32
+ def test_leading_empty_columns_are_preserved_with_delimiter
33
+ column_names = "A\tB\tC\tD"
34
+ data = "\t\t3\t4" # first two columns are empty data.
35
+
36
+ assert_equal({"A" => "", "B" => "", "C" => "3", "D" => "4"}, Rets::Parser::Compact.parse(column_names, data, "\t"))
37
+ end
38
+
39
+ def test_parse_empty_document
40
+ rows = Rets::Parser::Compact.parse_document(EMPTY_COMPACT)
41
+ assert_equal [], rows
42
+ end
43
+
44
+ def test_get_count
45
+ count = Rets::Parser::Compact.get_count(COUNT_ONLY)
46
+ assert_equal 1234, count
47
+ end
48
+
49
+ def test_get_count_with_no_matching_records
50
+ count = Rets::Parser::Compact.get_count(RETS_STATUS_NO_MATCHING_RECORDS)
51
+ assert_equal 0, count
52
+ end
53
+
54
+ def test_get_count_with_unrecognized_document
55
+ count = Rets::Parser::Compact.get_count("")
56
+ assert_equal 0, count
57
+ end
58
+
59
+ def test_parse_example
60
+ rows = Rets::Parser::Compact.parse_document(SAMPLE_COMPACT)
61
+
62
+ assert_equal "7", rows.first["MetadataEntryID"]
63
+ end
64
+
65
+ def test_parse_example_2
66
+ rows = Rets::Parser::Compact.parse_document(SAMPLE_COMPACT_2)
67
+
68
+ assert_equal "", rows.first["ModTimeStamp"]
69
+ end
70
+
71
+ def test_parse_with_changed_delimiter
72
+ rows = Rets::Parser::Compact.parse_document(CHANGED_DELIMITER)
73
+
74
+ assert_equal [{"A" => "1", "B" => "2"}, {"A" => "4", "B" => "5"}], rows
75
+ end
76
+
77
+ def test_parse_html_encoded_chars
78
+ rows = Rets::Parser::Compact.parse_document(SAMPLE_COMPACT_WITH_SPECIAL_CHARS)
79
+
80
+ assert_equal "porte-coch\u{E8}re welcomes ", rows.last["PublicRemarksNew"]
81
+ end
82
+
83
+ def test_parse_html_encoded_chars_2
84
+ rows = Rets::Parser::Compact.parse_document(SAMPLE_COMPACT_WITH_SPECIAL_CHARS_2)
85
+
86
+ assert_equal "text with <tag>", rows.last["PublicRemarksNew"]
87
+ end
88
+
89
+ def test_parse_doubly_encoded_bad_character_references
90
+ rows = Rets::Parser::Compact.parse_document(SAMPLE_COMPACT_WITH_DOUBLY_ENCODED_BAD_CHARACTER_REFERENCES)
91
+ assert_equal "foo bar", rows.last["PublicRemarksNew"]
92
+ end
93
+
94
+ def test_parse_property_with_lots_of_columns
95
+ row = Rets::Parser::Compact.parse_document(SAMPLE_PROPERTY_WITH_LOTS_OF_COLUMNS).first
96
+ assert_equal 800, row.keys.size
97
+ assert_equal 800.times.map { |x| "K%03d" % x }, row.keys
98
+ end
99
+
100
+ def test_safely_decode_character_references!
101
+ assert_decoded "a", "&#97;"
102
+ assert_decoded "a", "&#097;"
103
+ assert_decoded "a", "&#x61;"
104
+ assert_decoded "a", "&#x061;"
105
+ assert_decoded "", "&#xDC04;"
106
+ assert_decoded "", "&#56324;"
107
+ assert_decoded "", "&#x2000FF;"
108
+ end
109
+
110
+
111
+ def assert_decoded(a, b)
112
+ recoded = Rets::Parser::Compact.safely_decode_character_references!(b)
113
+ assert_equal a, recoded
114
+ end
115
+ end
@@ -0,0 +1,39 @@
1
+ require_relative "helper"
2
+
3
+ class TestParserMultipart < MiniTest::Test
4
+ def test_parse_returns_multiple_parts
5
+ headers = {"content-type"=>"image/jpeg", "content-id"=>"90020062739", "content-length"=>"10"}
6
+
7
+ parts = Rets::Parser::Multipart.parse(MULITPART_RESPONSE, "simple boundary")
8
+
9
+ assert_equal 2, parts.size
10
+
11
+ part = parts[0]
12
+
13
+ assert_equal headers.merge("object-id" => "1"), part.headers
14
+ assert_equal "xxxxxxxx", part.body.strip
15
+
16
+ part = parts[1]
17
+
18
+ assert_equal headers.merge("object-id" => "2"), part.headers
19
+ assert_equal "yyyyyyyy", part.body.strip
20
+ end
21
+
22
+ def test_parse_real_mls_data
23
+ parts = Rets::Parser::Multipart.parse(MULTIPART_RESPONSE_URLS, "rets.object.content.boundary.1330546052739")
24
+ assert_equal 5, parts.size
25
+ end
26
+
27
+ def test_parse_values_with_colon_data
28
+ parts = Rets::Parser::Multipart.parse(MULTIPART_RESPONSE_URLS, "rets.object.content.boundary.1330546052739")
29
+ assert_equal 'http://foobarmls.com/RETS//MediaDisplay/98/hr2890998-1.jpg', parts[0].headers['location']
30
+ end
31
+
32
+ def test_parse_with_error
33
+ raw = "\r\n--89467f8e0c6b48158c8f1883910212ec\r\nContent-Type: text/xml\r\nContent-ID: foo\r\nObject-ID: *\r\n\r\n<RETS ReplyCode=\"999\" ReplyText=\"An Unexplaned Error\" />\r\n\r\n--89467f8e0c6b48158c8f1883910212ec--\r\n"
34
+ boundary = "89467f8e0c6b48158c8f1883910212ec"
35
+ assert_raises Rets::InvalidRequest do
36
+ Rets::Parser::Multipart.parse(raw, boundary)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "helper"
2
+
3
+ require "stringio"
4
+
5
+ class TestYamlSerializer < MiniTest::Test
6
+
7
+ def setup
8
+ @serializer = Rets::Metadata::YamlSerializer.new
9
+ end
10
+
11
+ def test_round_trip
12
+ metadata = {"foo" => "bar"}
13
+ file = StringIO.new
14
+ @serializer.save(file, metadata)
15
+ file.rewind
16
+ loaded = @serializer.load(file)
17
+ assert_equal metadata, loaded
18
+ end
19
+
20
+ def test_bad_data
21
+ file = StringIO.new("\x01")
22
+ loaded = @serializer.load(file)
23
+ assert_nil loaded
24
+ end
25
+
26
+ end
@@ -0,0 +1,262 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://rets.example.com/GetObject.asmx/GetObject
6
+ body:
7
+ encoding: US-ASCII
8
+ string: Resource=Property&Type=Photo&ID=2661580%3A1&Location=0
9
+ headers:
10
+ User-Agent:
11
+ - Estately/1.0
12
+ Host:
13
+ - rets.example.com:80
14
+ Rets-Version:
15
+ - RETS/1.7.2
16
+ Authorization:
17
+ - Digest username="login", realm="fake_realm", qop="auth",
18
+ uri="/Login.asmx/Login", nonce="a8f4bc805062602c8ba7a87b2109f808", nc=00000001,
19
+ cnonce="6e2dd038eea6cbacf0b956fd11f914b6", response="fake_digest",
20
+ opaque="96eda461-41d0-4624-b7fe-b59e966035f3"
21
+ Cookie:
22
+ - ASP.NET_SessionId=mapij045k3bphj3gqqgpmmrx
23
+ Accept:
24
+ - image/jpeg, image/png;q=0.5, image/gif;q=0.1
25
+ Content-Type:
26
+ - application/x-www-form-urlencoded
27
+ Content-Length:
28
+ - '54'
29
+ response:
30
+ status:
31
+ code: 401
32
+ message: Unauthorized
33
+ headers:
34
+ Connection:
35
+ - close
36
+ Date:
37
+ - Thu, 26 Jul 2012 00:11:02 GMT
38
+ Server:
39
+ - Microsoft-IIS/6.0
40
+ Cache-Control:
41
+ - private
42
+ - private
43
+ X-Aspnet-Version:
44
+ - 2.0.50727
45
+ Www-Authenticate:
46
+ - Digest realm="fake_realm",nonce="dfd74deac03147e1a4fff598679f1a80",opaque="8e5029c6-bb9c-4562-b440-e7c2b8960743",qop="auth"
47
+ Content-Type:
48
+ - text/plain
49
+ body:
50
+ encoding: US-ASCII
51
+ string: ! "Unauthorized Request. Digest Session Invalid Reauthenticate\r\nReference:
52
+ e0ff89c0-2d64-4287-a6b7-6be27c7d3ade"
53
+ http_version:
54
+ recorded_at: Thu, 26 Jul 2012 00:11:13 GMT
55
+ - request:
56
+ method: post
57
+ uri: http://rets.example.com/Login.asmx/Login
58
+ body:
59
+ encoding: US-ASCII
60
+ string: ''
61
+ headers:
62
+ User-Agent:
63
+ - Estately/1.0
64
+ Host:
65
+ - rets.example.com:80
66
+ Rets-Version:
67
+ - RETS/1.7.2
68
+ Accept:
69
+ - ! '*/*'
70
+ response:
71
+ status:
72
+ code: 401
73
+ message: Unauthorized
74
+ headers:
75
+ Connection:
76
+ - close
77
+ Date:
78
+ - Thu, 26 Jul 2012 00:11:03 GMT
79
+ Server:
80
+ - Microsoft-IIS/6.0
81
+ Cache-Control:
82
+ - private
83
+ - private
84
+ X-Aspnet-Version:
85
+ - 2.0.50727
86
+ Www-Authenticate:
87
+ - Digest realm="fake_realm",nonce="17fdfe2c6125296bd93bb81bd88dc4be",opaque="aee1e7da-60eb-41b3-b704-8eb3969645fd",qop="auth"
88
+ Content-Type:
89
+ - text/plain
90
+ body:
91
+ encoding: US-ASCII
92
+ string: ! "Unauthorized Request. Authentication needed\r\nReference: c2c5ab9f-8c12-42bb-94ce-5b6ebf156da4"
93
+ http_version:
94
+ recorded_at: Thu, 26 Jul 2012 00:11:13 GMT
95
+ - request:
96
+ method: post
97
+ uri: http://rets.example.com/Login.asmx/Login
98
+ body:
99
+ encoding: US-ASCII
100
+ string: ''
101
+ headers:
102
+ User-Agent:
103
+ - Estately/1.0
104
+ Host:
105
+ - rets.example.com:80
106
+ Rets-Version:
107
+ - RETS/1.7.2
108
+ Authorization:
109
+ - Digest username="login", realm="fake_realm", qop="auth",
110
+ uri="/Login.asmx/Login", nonce="17fdfe2c6125296bd93bb81bd88dc4be", nc=00000001,
111
+ cnonce="ad805b9e2d6f08ad82175085e5febd8d", response="7402076f53663602f052e1aa343d3dab",
112
+ opaque="aee1e7da-60eb-41b3-b704-8eb3969645fd"
113
+ Accept:
114
+ - ! '*/*'
115
+ response:
116
+ status:
117
+ code: 200
118
+ message: OK
119
+ headers:
120
+ Date:
121
+ - Thu, 26 Jul 2012 00:11:03 GMT
122
+ Server:
123
+ - Microsoft-IIS/6.0
124
+ Cache-Control:
125
+ - private
126
+ - private, max-age=0
127
+ X-Aspnet-Version:
128
+ - 2.0.50727
129
+ Rets-Version:
130
+ - RETS/1.7.2
131
+ Rets-Server:
132
+ - Interealty-RETS/1.5.247.0
133
+ Transfer-Encoding:
134
+ - chunked
135
+ Set-Cookie:
136
+ - ASP.NET_SessionId=vuesmq55l0cpjy45zyn0e555; path=/; HttpOnly
137
+ - RETS-Session-ID=vuesmq55l0cpjy45zyn0e555; path=/
138
+ Content-Type:
139
+ - text/xml
140
+ body:
141
+ encoding: US-ASCII
142
+ string: ! "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<RETS ReplyCode=\"0\"
143
+ ReplyText=\"Success. Reference ID: a3073726-a011-4391-b22e-900adae5184b\">\r\n
144
+ \ <RETS-RESPONSE>\r\nMemberName=John Wolff\r\nUser=23756,60,RH,login\r\nBroker=BRDA,BRDA01\r\nMetadataVersion=31.76.69587\r\nMetadataTimeStamp=2012-07-24T17:33:07Z\r\nMinMetadataTimeStamp=2012-07-24T17:33:07Z\r\nTimeoutSeconds=7200\r\nChangePassword=/ChangePassword.asmx/ChangePassword\r\nGetObject=/GetObject.asmx/GetObject\r\nLogin=/Login.asmx/Login\r\nLogout=/Logout.asmx/Logout\r\nSearch=/Search.asmx/Search\r\nGetMetadata=/GetMetadata.asmx/GetMetadata\r\n</RETS-RESPONSE>\r\n</RETS>"
145
+ http_version:
146
+ recorded_at: Thu, 26 Jul 2012 00:11:14 GMT
147
+ - request:
148
+ method: post
149
+ uri: http://rets.example.com/Login.asmx/Login
150
+ body:
151
+ encoding: US-ASCII
152
+ string: ''
153
+ headers:
154
+ User-Agent:
155
+ - Estately/1.0
156
+ Host:
157
+ - rets.example.com:80
158
+ Rets-Version:
159
+ - RETS/1.7.2
160
+ Authorization:
161
+ - Digest username="login", realm="fake_realm", qop="auth",
162
+ uri="/Login.asmx/Login", nonce="17fdfe2c6125296bd93bb81bd88dc4be", nc=00000001,
163
+ cnonce="ad805b9e2d6f08ad82175085e5febd8d", response="7402076f53663602f052e1aa343d3dab",
164
+ opaque="aee1e7da-60eb-41b3-b704-8eb3969645fd"
165
+ Cookie:
166
+ - ASP.NET_SessionId=vuesmq55l0cpjy45zyn0e555; RETS-Session-ID=vuesmq55l0cpjy45zyn0e555
167
+ Accept:
168
+ - ! '*/*'
169
+ response:
170
+ status:
171
+ code: 200
172
+ message: OK
173
+ headers:
174
+ Date:
175
+ - Thu, 26 Jul 2012 00:11:03 GMT
176
+ Server:
177
+ - Microsoft-IIS/6.0
178
+ Cache-Control:
179
+ - private
180
+ - private, max-age=0
181
+ X-Aspnet-Version:
182
+ - 2.0.50727
183
+ Rets-Version:
184
+ - RETS/1.7.2
185
+ Rets-Server:
186
+ - Interealty-RETS/1.5.247.0
187
+ Transfer-Encoding:
188
+ - chunked
189
+ Set-Cookie:
190
+ - RETS-Session-ID=vuesmq55l0cpjy45zyn0e555; path=/
191
+ Content-Type:
192
+ - text/xml
193
+ body:
194
+ encoding: US-ASCII
195
+ string: ! "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<RETS ReplyCode=\"0\"
196
+ ReplyText=\"Success. Reference ID: a48b4f59-cb22-41be-8e7b-1cee28fb8644\">\r\n
197
+ \ <RETS-RESPONSE>\r\nMemberName=John Wolff\r\nUser=23756,60,RH,login\r\nBroker=BRDA,BRDA01\r\nMetadataVersion=31.76.69587\r\nMetadataTimeStamp=2012-07-24T17:33:07Z\r\nMinMetadataTimeStamp=2012-07-24T17:33:07Z\r\nTimeoutSeconds=7200\r\nChangePassword=/ChangePassword.asmx/ChangePassword\r\nGetObject=/GetObject.asmx/GetObject\r\nLogin=/Login.asmx/Login\r\nLogout=/Logout.asmx/Logout\r\nSearch=/Search.asmx/Search\r\nGetMetadata=/GetMetadata.asmx/GetMetadata\r\n</RETS-RESPONSE>\r\n</RETS>"
198
+ http_version:
199
+ recorded_at: Thu, 26 Jul 2012 00:11:14 GMT
200
+ - request:
201
+ method: post
202
+ uri: http://rets.example.com/GetObject.asmx/GetObject
203
+ body:
204
+ encoding: US-ASCII
205
+ string: Resource=Property&Type=Photo&ID=2661580%3A1&Location=0
206
+ headers:
207
+ User-Agent:
208
+ - Estately/1.0
209
+ Host:
210
+ - rets.example.com:80
211
+ Rets-Version:
212
+ - RETS/1.7.2
213
+ Authorization:
214
+ - Digest username="login", realm="fake_realm", qop="auth",
215
+ uri="/Login.asmx/Login", nonce="17fdfe2c6125296bd93bb81bd88dc4be", nc=00000001,
216
+ cnonce="ad805b9e2d6f08ad82175085e5febd8d", response="7402076f53663602f052e1aa343d3dab",
217
+ opaque="aee1e7da-60eb-41b3-b704-8eb3969645fd"
218
+ Cookie:
219
+ - ASP.NET_SessionId=vuesmq55l0cpjy45zyn0e555; RETS-Session-ID=vuesmq55l0cpjy45zyn0e555
220
+ Accept:
221
+ - image/jpeg, image/png;q=0.5, image/gif;q=0.1
222
+ Content-Type:
223
+ - application/x-www-form-urlencoded
224
+ Content-Length:
225
+ - '54'
226
+ response:
227
+ status:
228
+ code: 200
229
+ message: OK
230
+ headers:
231
+ Date:
232
+ - Thu, 26 Jul 2012 00:11:04 GMT
233
+ Server:
234
+ - Microsoft-IIS/6.0
235
+ Cache-Control:
236
+ - private
237
+ - private, max-age=0
238
+ X-Aspnet-Version:
239
+ - 2.0.50727
240
+ Mime-Version:
241
+ - '1.0'
242
+ Rets-Version:
243
+ - RETS/1.7.2
244
+ Rets-Server:
245
+ - Interealty-RETS/1.5.247.0
246
+ Content-Id:
247
+ - '2661580'
248
+ Object-Id:
249
+ - '1'
250
+ Transfer-Encoding:
251
+ - chunked
252
+ Set-Cookie:
253
+ - RETS-Session-ID=vuesmq55l0cpjy45zyn0e555; path=/
254
+ Content-Type:
255
+ - image/jpeg
256
+ body:
257
+ encoding: ASCII-8BIT
258
+ string: !binary |-
259
+ /9j/4AAQSkZJRgABAQEAYABgAAD///2Q==
260
+ http_version:
261
+ recorded_at: Thu, 26 Jul 2012 00:11:14 GMT
262
+ recorded_with: VCR 2.2.2
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rets-hack
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.11'
5
+ platform: ruby
6
+ authors:
7
+ - Estately, Inc. Open Source
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpclient
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.7.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.7.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: http-cookie
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.1.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: vcr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.8'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: hoe
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.15'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.15'
125
+ description: |-
126
+ [![Build Status](https://secure.travis-ci.org/estately/rets.png?branch=master)](http://travis-ci.org/estately/rets)
127
+ A pure-ruby library for fetching data from [RETS] servers.
128
+
129
+ If you're looking for a slick CLI interface check out [retscli](https://github.com/summera/retscli), which is an awesome tool for exploring metadata or learning about RETS.
130
+
131
+ [RETS]: http://www.rets.org
132
+ email:
133
+ - opensource@estately.com
134
+ executables:
135
+ - rets
136
+ extensions: []
137
+ extra_rdoc_files:
138
+ - CHANGELOG.md
139
+ - Manifest.txt
140
+ - README.md
141
+ files:
142
+ - CHANGELOG.md
143
+ - Manifest.txt
144
+ - README.md
145
+ - Rakefile
146
+ - bin/rets
147
+ - example/connect.rb
148
+ - example/get-photos.rb
149
+ - example/get-property.rb
150
+ - lib/rets.rb
151
+ - lib/rets/client.rb
152
+ - lib/rets/client_progress_reporter.rb
153
+ - lib/rets/http_client.rb
154
+ - lib/rets/locking_http_client.rb
155
+ - lib/rets/measuring_http_client.rb
156
+ - lib/rets/metadata.rb
157
+ - lib/rets/metadata/caching.rb
158
+ - lib/rets/metadata/containers.rb
159
+ - lib/rets/metadata/file_cache.rb
160
+ - lib/rets/metadata/json_serializer.rb
161
+ - lib/rets/metadata/lookup_table.rb
162
+ - lib/rets/metadata/lookup_type.rb
163
+ - lib/rets/metadata/marshal_serializer.rb
164
+ - lib/rets/metadata/multi_lookup_table.rb
165
+ - lib/rets/metadata/null_cache.rb
166
+ - lib/rets/metadata/resource.rb
167
+ - lib/rets/metadata/rets_class.rb
168
+ - lib/rets/metadata/rets_object.rb
169
+ - lib/rets/metadata/root.rb
170
+ - lib/rets/metadata/table.rb
171
+ - lib/rets/metadata/table_factory.rb
172
+ - lib/rets/metadata/yaml_serializer.rb
173
+ - lib/rets/parser/compact.rb
174
+ - lib/rets/parser/error_checker.rb
175
+ - lib/rets/parser/multipart.rb
176
+ - test/fixtures.rb
177
+ - test/helper.rb
178
+ - test/test_caching.rb
179
+ - test/test_client.rb
180
+ - test/test_error_checker.rb
181
+ - test/test_file_cache.rb
182
+ - test/test_http_client.rb
183
+ - test/test_json_serializer.rb
184
+ - test/test_locking_http_client.rb
185
+ - test/test_marshal_serializer.rb
186
+ - test/test_metadata.rb
187
+ - test/test_metadata_class.rb
188
+ - test/test_metadata_lookup_table.rb
189
+ - test/test_metadata_lookup_type.rb
190
+ - test/test_metadata_multi_lookup_table.rb
191
+ - test/test_metadata_object.rb
192
+ - test/test_metadata_resource.rb
193
+ - test/test_metadata_root.rb
194
+ - test/test_metadata_table.rb
195
+ - test/test_metadata_table_factory.rb
196
+ - test/test_parser_compact.rb
197
+ - test/test_parser_multipart.rb
198
+ - test/test_yaml_serializer.rb
199
+ - test/vcr_cassettes/unauthorized_response.yml
200
+ homepage: http://github.com/mlessard/rets
201
+ licenses:
202
+ - MIT
203
+ metadata: {}
204
+ post_install_message:
205
+ rdoc_options:
206
+ - "--main"
207
+ - README.md
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ required_rubygems_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ requirements: []
221
+ rubyforge_project:
222
+ rubygems_version: 2.4.5
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: "[![Build Status](https://secure.travis-ci.org/estately/rets.png?branch=master)](http://travis-ci.org/estately/rets)
226
+ A pure-ruby library for fetching data from [RETS] servers"
227
+ test_files: []