rets4r 0.8.5 → 1.1.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/{test/client/data/1.5/metadata.xml → .gemtest} +0 -0
- data/CHANGELOG +611 -66
- data/CONTRIBUTORS +6 -2
- data/Gemfile +1 -0
- data/LICENSE +22 -0
- data/MANIFEST +63 -0
- data/NEWS +203 -0
- data/{README → README.rdoc} +11 -4
- data/RUBYS +7 -7
- data/Rakefile +48 -0
- data/TODO +5 -1
- data/examples/client_get_object.rb +31 -42
- data/examples/client_login.rb +20 -18
- data/examples/client_mapper.rb +17 -0
- data/examples/client_metadata.rb +28 -28
- data/examples/client_parser.rb +9 -0
- data/examples/client_search.rb +25 -27
- data/examples/settings.yml +114 -0
- data/lib/rets4r.rb +14 -1
- data/lib/rets4r/auth.rb +70 -66
- data/lib/rets4r/client.rb +470 -650
- data/lib/rets4r/client/data.rb +13 -13
- data/lib/rets4r/client/dataobject.rb +27 -19
- data/lib/rets4r/client/exceptions.rb +116 -0
- data/lib/rets4r/client/links.rb +32 -0
- data/lib/rets4r/client/metadata.rb +12 -12
- data/lib/rets4r/client/parsers/compact.rb +42 -0
- data/lib/rets4r/client/parsers/compact_nokogiri.rb +91 -0
- data/lib/rets4r/client/parsers/metadata.rb +92 -0
- data/lib/rets4r/client/parsers/response_parser.rb +100 -0
- data/lib/rets4r/client/requester.rb +143 -0
- data/lib/rets4r/client/transaction.rb +30 -33
- data/lib/rets4r/core_ext/array/extract_options.rb +15 -0
- data/lib/rets4r/core_ext/class/attribute_accessors.rb +58 -0
- data/lib/rets4r/core_ext/hash/keys.rb +46 -0
- data/lib/rets4r/core_ext/hash/slice.rb +39 -0
- data/lib/rets4r/listing_mapper.rb +17 -0
- data/lib/rets4r/listing_service.rb +35 -0
- data/lib/rets4r/loader.rb +8 -0
- data/lib/tasks/annotations.rake +121 -0
- data/lib/tasks/coverage.rake +13 -0
- data/rets4r.gemspec +24 -0
- data/spec/rets4r_compact_data_parser_spec.rb +7 -0
- data/test/data/1.5/bad_compact.xml +7 -0
- data/test/data/1.5/count_only_compact.xml +3 -0
- data/test/{client/data → data}/1.5/error.xml +0 -0
- data/test/{client/data → data}/1.5/invalid_compact.xml +0 -0
- data/test/{client/data → data}/1.5/login.xml +0 -0
- data/test/data/1.5/metadata.xml +0 -0
- data/test/{client/data → data}/1.5/search_compact.xml +0 -0
- data/test/data/1.5/search_compact_big.xml +136 -0
- data/test/{client/data → data}/1.5/search_unescaped_compact.xml +0 -0
- data/test/data/listing_service.yml +36 -0
- data/test/test_auth.rb +68 -0
- data/test/test_client.rb +342 -0
- data/test/test_client_links.rb +39 -0
- data/test/test_compact_nokogiri.rb +64 -0
- data/test/test_helper.rb +12 -0
- data/test/test_listing_mapper.rb +112 -0
- data/test/test_loader.rb +24 -0
- data/test/test_parser.rb +96 -0
- data/test/test_quality.rb +57 -0
- metadata +168 -53
- data/GPL +0 -340
- data/examples/metadata.xml +0 -42
- data/lib/rets4r/client/metadataindex.rb +0 -82
- data/lib/rets4r/client/parser.rb +0 -141
- data/lib/rets4r/client/parser/rexml.rb +0 -75
- data/lib/rets4r/client/parser/xmlparser.rb +0 -95
- data/test/client/parser/tc_rexml.rb +0 -17
- data/test/client/parser/tc_xmlparser.rb +0 -21
- data/test/client/tc_auth.rb +0 -68
- data/test/client/tc_client.rb +0 -320
- data/test/client/tc_metadataindex.rb +0 -36
- data/test/client/test_parser.rb +0 -128
- data/test/client/ts_all.rb +0 -8
- data/test/ts_all.rb +0 -1
- data/test/ts_client.rb +0 -1
@@ -0,0 +1,17 @@
|
|
1
|
+
module RETS4R
|
2
|
+
class ListingMapper
|
3
|
+
def initialize(params = {})
|
4
|
+
@select = params[:select] || ListingService.connection[:select]
|
5
|
+
end
|
6
|
+
def select
|
7
|
+
@select
|
8
|
+
end
|
9
|
+
def map(original)
|
10
|
+
listing = {}
|
11
|
+
@select.each_pair {|rets_key, record_key|
|
12
|
+
listing[record_key] = original[rets_key]
|
13
|
+
}
|
14
|
+
listing
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rets4r/core_ext/class/attribute_accessors'
|
2
|
+
require 'rets4r/core_ext/hash/keys'
|
3
|
+
require 'rets4r/core_ext/hash/slice'
|
4
|
+
|
5
|
+
module RETS4R
|
6
|
+
class ListingService
|
7
|
+
# RECORD_COUNT_ONLY=Librets::SearchRequest::RECORD_COUNT_ONLY
|
8
|
+
RECORD_COUNT_ONLY='fixme'
|
9
|
+
# Contains the listing service configurations - typically stored in
|
10
|
+
# config/listing_service.yml - as a Hash.
|
11
|
+
cattr_accessor :configurations, :instance_writer => false
|
12
|
+
cattr_accessor :env, :instance_writer => false
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
# Connection configuration for the specified environment, or the current
|
17
|
+
# environment if none is given.
|
18
|
+
def connection(spec = nil)
|
19
|
+
case spec
|
20
|
+
when nil
|
21
|
+
connection(RETS4R::ListingService.env)
|
22
|
+
when Symbol, String
|
23
|
+
if configuration = configurations[spec.to_s]
|
24
|
+
configuration.symbolize_keys
|
25
|
+
else
|
26
|
+
raise ArgumentError, "#{spec} listing service is not configured"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise ArgumentError, "#{spec} listing service is not configured"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end # class << self
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Implements the logic behind the rake tasks for annotations like
|
2
|
+
#
|
3
|
+
# rake notes
|
4
|
+
# rake notes:optimize
|
5
|
+
#
|
6
|
+
# and friends. See <tt>rake -T notes</tt> and <tt>railties/lib/tasks/annotations.rake</tt>.
|
7
|
+
#
|
8
|
+
# Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that
|
9
|
+
# represent the line where the annotation lives, its tag, and its text. Note
|
10
|
+
# the filename is not stored.
|
11
|
+
#
|
12
|
+
# Annotations are looked for in comments and modulus whitespace they have to
|
13
|
+
# start with the tag optionally followed by a colon. Everything up to the end
|
14
|
+
# of the line (or closing ERb comment tag) is considered to be their text.
|
15
|
+
class SourceAnnotationExtractor
|
16
|
+
class Annotation < Struct.new(:line, :tag, :text)
|
17
|
+
|
18
|
+
# Returns a representation of the annotation that looks like this:
|
19
|
+
#
|
20
|
+
# [126] [TODO] This algorithm is simple and clearly correct, make it faster.
|
21
|
+
#
|
22
|
+
# If +options+ has a flag <tt>:tag</tt> the tag is shown as in the example above.
|
23
|
+
# Otherwise the string contains just line and text.
|
24
|
+
def to_s(options={})
|
25
|
+
s = "[%3d] " % line
|
26
|
+
s << "[#{tag}] " if options[:tag]
|
27
|
+
s << text
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Prints all annotations with tag +tag+ under the root directories +app+, +lib+,
|
32
|
+
# and +test+ (recursively). Only filenames with extension +.builder+, +.rb+,
|
33
|
+
# +.rxml+, +.rjs+, +.rhtml+, or +.erb+ are taken into account. The +options+
|
34
|
+
# hash is passed to each annotation's +to_s+.
|
35
|
+
#
|
36
|
+
# This class method is the single entry point for the rake tasks.
|
37
|
+
def self.enumerate(tag, options={})
|
38
|
+
extractor = new(tag)
|
39
|
+
extractor.display(extractor.find, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :tag
|
43
|
+
|
44
|
+
def initialize(tag)
|
45
|
+
@tag = tag
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a hash that maps filenames under +dirs+ (recursively) to arrays
|
49
|
+
# with their annotations. Only files with annotations are included, and only
|
50
|
+
# those with extension +.builder+, +.rb+, +.rxml+, +.rjs+, +.rhtml+, and +.erb+
|
51
|
+
# are taken into account.
|
52
|
+
def find(dirs=%w(app lib test))
|
53
|
+
dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns a hash that maps filenames under +dir+ (recursively) to arrays
|
57
|
+
# with their annotations. Only files with annotations are included, and only
|
58
|
+
# those with extension +.builder+, +.rb+, +.rxml+, +.rjs+, +.rhtml+, and +.erb+
|
59
|
+
# are taken into account.
|
60
|
+
def find_in(dir)
|
61
|
+
results = {}
|
62
|
+
|
63
|
+
Dir.glob("#{dir}/*") do |item|
|
64
|
+
next if File.basename(item)[0] == ?.
|
65
|
+
|
66
|
+
if File.directory?(item)
|
67
|
+
results.update(find_in(item))
|
68
|
+
elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
|
69
|
+
results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
|
70
|
+
elsif item =~ /\.(rhtml|erb)$/
|
71
|
+
results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
results
|
76
|
+
end
|
77
|
+
|
78
|
+
# If +file+ is the filename of a file that contains annotations this method returns
|
79
|
+
# a hash with a single entry that maps +file+ to an array of its annotations.
|
80
|
+
# Otherwise it returns an empty hash.
|
81
|
+
def extract_annotations_from(file, pattern)
|
82
|
+
lineno = 0
|
83
|
+
result = File.readlines(file).inject([]) do |list, line|
|
84
|
+
lineno += 1
|
85
|
+
next list unless line =~ pattern
|
86
|
+
list << Annotation.new(lineno, $1, $2)
|
87
|
+
end
|
88
|
+
result.empty? ? {} : { file => result }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Prints the mapping from filenames to annotations in +results+ ordered by filename.
|
92
|
+
# The +options+ hash is passed to each annotation's +to_s+.
|
93
|
+
def display(results, options={})
|
94
|
+
results.keys.sort.each do |file|
|
95
|
+
puts "#{file}:"
|
96
|
+
results[file].each do |note|
|
97
|
+
puts " * #{note.to_s(options)}"
|
98
|
+
end
|
99
|
+
puts
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "Enumerate all annotations"
|
105
|
+
task :notes do
|
106
|
+
SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
|
107
|
+
end
|
108
|
+
|
109
|
+
namespace :notes do
|
110
|
+
["OPTIMIZE", "FIXME", "TODO"].each do |annotation|
|
111
|
+
desc "Enumerate all #{annotation} annotations"
|
112
|
+
task annotation.downcase.intern do
|
113
|
+
SourceAnnotationExtractor.enumerate annotation
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
desc "Enumerate a custom annotation, specify with ANNOTATION=WTFHAX"
|
118
|
+
task :custom do
|
119
|
+
SourceAnnotationExtractor.enumerate ENV['ANNOTATION']
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
begin
|
2
|
+
require 'rcov/rcovtask'
|
3
|
+
Rcov::RcovTask.new do |test|
|
4
|
+
test.libs << 'test'
|
5
|
+
test.pattern = "test/test_*.rb"
|
6
|
+
test.verbose = true
|
7
|
+
test.rcov_opts << ' --sort coverage'
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
task :rcov do
|
11
|
+
abort "RCov is not available. In order to run rcov, you must: gem install rcov"
|
12
|
+
end
|
13
|
+
end
|
data/rets4r.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
lib = File.expand_path("../lib/rets4r.rb", __FILE__)
|
2
|
+
version = File.read(lib)[/^\s*VERSION\s*=\s*(['"])(\d\.\d\.\d+)\1/, 2]
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'rets4r'
|
6
|
+
spec.authors = ["Scott Patterson", "John Wulff", "bgetting", "Jacob Basham", "Joseph Holsten"]
|
7
|
+
spec.email = ["scott.patterson@digitalaun.com", "john@johnwulff.com", "brian@terra-firma-design.com", "jacob@paperpigeons.net", "joseph@josephholsten.com"]
|
8
|
+
spec.homepage = 'http://rets4r.rubyforge.org/'
|
9
|
+
spec.rubyforge_project = 'rets4r'
|
10
|
+
spec.description = %q{RETS4R is a native Ruby interface to the RETS (Real Estate Transaction Standard). It currently is built for the 1.5 specification, but support for 1.7 and 2.0 are planned. It does not currently implement all of the specification, but the most commonly used portions. Specifically, there is no support for Update transactions.}
|
11
|
+
spec.extra_rdoc_files = %w[CHANGELOG CONTRIBUTORS LICENSE MANIFEST NEWS README.rdoc RUBYS TODO ]
|
12
|
+
spec.rdoc_options << "--charset=UTF-8" <<
|
13
|
+
"--main" << "README.rdoc"
|
14
|
+
spec.version = version
|
15
|
+
spec.summary = spec.description.split(/\.\s+/).first
|
16
|
+
spec.files = File.read("MANIFEST").split(/\r?\n\r?/)
|
17
|
+
|
18
|
+
spec.add_runtime_dependency 'nokogiri', '~>1.4.3.0'
|
19
|
+
spec.add_development_dependency 'mocha'
|
20
|
+
spec.add_development_dependency 'shoulda'
|
21
|
+
spec.add_development_dependency 'activesupport'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<RETS ReplyCode="0" ReplyText="Operation Successful">
|
2
|
+
<COUNT Records="38610" />
|
3
|
+
<DELIMITER value="09" />
|
4
|
+
<COLUMNS> MLSNUM AGENTLIST AGENTLIST_FULLNAME OFFICELIST OFFICELIST_OFFICENAM1 INTERNETLIST_ALL LISTSTATUSFLAG PHOTOCOUNT LISTSTATUS BEDS CARPORTCAP NUMDININGAREAS FIREPLACES BATHSFULL BATHSFULLLEVEL1 BATHSFULLLEVEL2 BATHSFULLLEVEL3 BATHSFULLBASEMENT GARAGECAP BATHSHALF BATHSHALFLEVEL1 BATHSHALFLEVEL2 BATHSHALFLEVEL3 BATHSHALFBASEMENT NUMLIVINGAREAS NUMBARNS NUMLAKES NUMPONDS NUMRESIDENCE NUMSTOCKTANKS STORIES NUMWELLS SCHOOLDISTRICT AGENTSELL_FULLNAME OFFICESELL_OFFICENAM2 STATE STREETNAME STREETTYPE STREETNUM STREETNUMDISPLAY STREETDIRSUFFIX STREETDIR STYLE SUBDIVISION ACRES INTERNETDISPLAYYN ROOMBEDBATHDESC STORIESBLDG CITY COMMONFEATURES COUNTY ACRESCULTIVATED INTERIOR LISTPRICE SQFTPRICE LOTNUM LOTDESC LOTDIM LOTSIZE LISTPRICELOW ACRESPRICE MAPBOOK MAPCOORD MAPPAGE LISTPRICEORIG GARAGEDESC PROPTYPE REMARKS PROPSUBTYPE PROPSUBTYPEDISPLAY SQFTTOTAL SQFTSOURCE UTILITIES UID UIDPRP TAXUNEXEMPT UNITNUM YEARBUILT ZIPCODE </COLUMNS>
|
5
|
+
<DATA> 11322886 000533246 CD Boyd, II FMAB McClure, REALTORS OMWS,immo,RCOM,SYND 8 act 4 0 2 1 3 2 0 2 2 Wylie ISD, Taylor Co. TX Thompson PKWY 8317 8317 STYRANCH Belle Vista Estates 0.361 Y BBFJET-TUB,BBFLIN-CLO,BBFSEP-SHO,BBFW+I-CLO Abilene Taylor INFBAY-WIN,INFCABLE-A,INFDECLTNG,INFHIGHSPD,INFLOFT,INFSOUND-W,INFVAUL-CL,INFWIND-CO 239000 84.6 LTDSUBDIV 87X182 LTS.5-.99A 0 662049 OT none 9999 239000 PARATTACHE,PAROPENER,PARREAR,PARSIDE RES Custom home built in 05'. Growing neighborhood convienient to Wylie schools. Abundant living areas and and open space floor plan.Could be 5th BDRM, or upstair BDRM & Bath could be another living area. Perfect office next to Master. Gourmet sized kitchen, granite countertops, barell ceilings, wonderful storage space!!!! S RES-S 2825 TAX STUASPHALT,UTLCITY-SE,UTLCITY-WA,STUCONCRET 3211078 3211078 5876 2005 79606-6652 </DATA>
|
6
|
+
<MAXROWS />
|
7
|
+
</RETS>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,136 @@
|
|
1
|
+
<RETS ReplyCode="0" ReplyText="SUCCESS">
|
2
|
+
<COUNT Records="4"/>
|
3
|
+
<DELIMITER value="09" />
|
4
|
+
<COLUMNS> First Second Third </COLUMNS>
|
5
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
6
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
7
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
8
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
9
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
10
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
11
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
12
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
13
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
14
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
15
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
16
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
17
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
18
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
19
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
20
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
21
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
22
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
23
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
24
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
25
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
26
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
27
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
28
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
29
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
30
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
31
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
32
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
33
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
34
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
35
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
36
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
37
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
38
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
39
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
40
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
41
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
42
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
43
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
44
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
45
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
46
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
47
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
48
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
49
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
50
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
51
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
52
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
53
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
54
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
55
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
56
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
57
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
58
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
59
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
60
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
61
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
62
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
63
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
64
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
65
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
66
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
67
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
68
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
69
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
70
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
71
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
72
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
73
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
74
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
75
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
76
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
77
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
78
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
79
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
80
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
81
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
82
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
83
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
84
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
85
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
86
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
87
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
88
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
89
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
90
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
91
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
92
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
93
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
94
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
95
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
96
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
97
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
98
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
99
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
100
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
101
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
102
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
103
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
104
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
105
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
106
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
107
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
108
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
109
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
110
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
111
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
112
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
113
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
114
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
115
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
116
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
117
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
118
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
119
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
120
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
121
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
122
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
123
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
124
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
125
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
126
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
127
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
128
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
129
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
130
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
131
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
132
|
+
<DATA> Datum1 Datum2 Datum3</DATA>
|
133
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
134
|
+
<DATA> Datum4 Datum5 Datum6</DATA>
|
135
|
+
<MAXROWS/>
|
136
|
+
</RETS>
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# This file specifies the access information for the listing service #
|
2
|
+
# To access the standard RETS demo server, use:
|
3
|
+
#
|
4
|
+
test:
|
5
|
+
url: http://demo.crt.realtors.org:6103/rets/login
|
6
|
+
username: Joe
|
7
|
+
password: Schmoe
|
8
|
+
version: 1.7.2
|
9
|
+
resource: Property
|
10
|
+
class: RES
|
11
|
+
object_type: Photo
|
12
|
+
select:
|
13
|
+
ListingID: :mls
|
14
|
+
AgentID: :agent_id
|
15
|
+
ModificationTimestamp: :rets_update_at
|
16
|
+
Status: :status
|
17
|
+
# ListDate: :list_date
|
18
|
+
ListPrice: :list_price
|
19
|
+
# ClosePrice: :close_price
|
20
|
+
# ContractDate: :contract_date
|
21
|
+
StreetNumber: :street_number
|
22
|
+
StreetName: :street_name
|
23
|
+
StreetDirection: :street_direction
|
24
|
+
Unit: :unit_number
|
25
|
+
ZipCode: :zip_code
|
26
|
+
City: :city
|
27
|
+
County: :county
|
28
|
+
# Rooms: :rooms
|
29
|
+
# State: :state
|
30
|
+
# Board: :board
|
31
|
+
LivingArea: :living_area
|
32
|
+
Baths: :baths
|
33
|
+
Bedrooms: :beds
|
34
|
+
Garage: :garage
|
35
|
+
SqFt: :square_feet
|
36
|
+
YearBuilt: :year_built
|
data/test/test_auth.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
|
3
|
+
require 'rets4r/auth'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
module RETS4R
|
7
|
+
class TestAuth < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@useragent = 'TestAgent/0.00'
|
10
|
+
@username = 'username'
|
11
|
+
@password = 'password'
|
12
|
+
@realm = 'REALM'
|
13
|
+
@nonce = '2006-03-03T17:37:10'
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_authenticate
|
17
|
+
response = {
|
18
|
+
'www-authenticate' => 'Digest qop="auth",realm="'+ @realm +'",nonce="'+ @nonce +'",opaque="",stale="false",domain="\my\test\domain"'
|
19
|
+
}
|
20
|
+
|
21
|
+
Auth.authenticate(response, @username, @password, '/my/rets/url', 'GET', Auth.request_id, @useragent)
|
22
|
+
end
|
23
|
+
|
24
|
+
# test without spacing
|
25
|
+
def test_parse_auth_header_without_spacing
|
26
|
+
header = 'Digest qop="auth",realm="'+ @realm +'",nonce="'+ @nonce +'",opaque="",stale="false",domain="\my\test\domain"'
|
27
|
+
check_header(header)
|
28
|
+
end
|
29
|
+
|
30
|
+
# test with spacing between each item
|
31
|
+
def test_parse_auth_header_with_spacing
|
32
|
+
header = 'Digest qop="auth", realm="'+ @realm +'", nonce="'+ @nonce +'", opaque="", stale="false", domain="\my\test\domain"'
|
33
|
+
check_header(header)
|
34
|
+
end
|
35
|
+
|
36
|
+
# used to check the that the header was processed properly.
|
37
|
+
def check_header(header)
|
38
|
+
results = Auth.parse_header(header)
|
39
|
+
|
40
|
+
assert_equal('auth', results['qop'])
|
41
|
+
assert_equal('REALM', results['realm'])
|
42
|
+
assert_equal('2006-03-03T17:37:10', results['nonce'])
|
43
|
+
assert_equal('', results['opaque'])
|
44
|
+
assert_equal('false', results['stale'])
|
45
|
+
assert_equal('\my\test\domain', results['domain'])
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_calculate_digest
|
49
|
+
# with qop
|
50
|
+
assert_equal('c5f9ef280f0ca78ed7a488158fc2f4cc', Auth.calculate_digest(@username, \
|
51
|
+
@password, @realm, 'test', 'GET', '/my/rets/url', true, 'test'))
|
52
|
+
|
53
|
+
# without qop
|
54
|
+
assert_equal('bceafa34467a3519c2f6295d4800f4ea', Auth.calculate_digest(@username, \
|
55
|
+
@password, @realm, 'test', 'GET', '/my/rets/url', false))
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_request_id
|
59
|
+
assert_not_nil(true, Auth.request_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_cnonce
|
63
|
+
# We call cnonce with a static request ID so that we have a consistent result with which
|
64
|
+
# to test against
|
65
|
+
assert_equal('d5cdfa1acffde590d263689fb40cf53c', Auth.cnonce(@useragent, @password, 'requestId', @nonce))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|