josephholsten-rets4r 1.1.17 → 1.1.18
Sign up to get free protection for your applications and to get access to all the features.
- metadata +44 -84
- data/CHANGELOG +0 -336
- data/CONTRIBUTORS +0 -7
- data/GPL +0 -340
- data/LICENSE +0 -29
- data/NEWS +0 -183
- data/README.rdoc +0 -45
- data/RUBYS +0 -56
- data/Rakefile +0 -57
- data/TODO +0 -29
- data/VERSION.yml +0 -5
- data/examples/client_get_object.rb +0 -47
- data/examples/client_login.rb +0 -37
- data/examples/client_metadata.rb +0 -40
- data/examples/client_parser.rb +0 -10
- data/examples/client_search.rb +0 -47
- data/examples/settings.yml +0 -12
- data/lib/rets4r.rb +0 -9
- data/lib/rets4r/auth.rb +0 -73
- data/lib/rets4r/client.rb +0 -723
- data/lib/rets4r/client/data.rb +0 -14
- data/lib/rets4r/client/dataobject.rb +0 -20
- data/lib/rets4r/client/metadata.rb +0 -15
- data/lib/rets4r/client/parsers/compact.rb +0 -42
- data/lib/rets4r/client/parsers/compact_nokogiri.rb +0 -81
- data/lib/rets4r/client/parsers/metadata.rb +0 -92
- data/lib/rets4r/client/parsers/response_parser.rb +0 -100
- data/lib/rets4r/client/transaction.rb +0 -31
- data/lib/rets4r/core_ext/array/extract_options.rb +0 -15
- data/lib/rets4r/core_ext/class/attribute_accessors.rb +0 -58
- data/lib/rets4r/core_ext/hash/keys.rb +0 -46
- data/lib/rets4r/core_ext/hash/slice.rb +0 -39
- data/lib/rets4r/listing_mapper.rb +0 -17
- data/lib/rets4r/listing_service.rb +0 -35
- data/lib/rets4r/loader.rb +0 -8
- data/lib/tasks/annotations.rake +0 -20
- data/lib/tasks/coverage.rake +0 -13
- data/test/compact_nokogiri_test.rb +0 -35
- data/test/data/1.5/bad_compact.xml +0 -7
- data/test/data/1.5/count_only_compact.xml +0 -3
- data/test/data/1.5/error.xml +0 -1
- data/test/data/1.5/invalid_compact.xml +0 -4
- data/test/data/1.5/login.xml +0 -16
- data/test/data/1.5/metadata.xml +0 -0
- data/test/data/1.5/search_compact.xml +0 -8
- data/test/data/1.5/search_compact_big.xml +0 -136
- data/test/data/1.5/search_unescaped_compact.xml +0 -8
- data/test/data/listing_service.yml +0 -36
- data/test/listing_mapper_test.rb +0 -112
- data/test/loader_test.rb +0 -24
- data/test/test_auth.rb +0 -68
- data/test/test_client.rb +0 -315
- data/test/test_helper.rb +0 -12
- data/test/test_parser.rb +0 -96
data/lib/rets4r/client/data.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
module RETS4R
|
2
|
-
class Client
|
3
|
-
# Represents a row of data. Nothing more than a glorfied Hash with a custom constructor and a
|
4
|
-
# type attribute.
|
5
|
-
class Data < ::Hash
|
6
|
-
attr_accessor :type
|
7
|
-
|
8
|
-
def initialize(type = false)
|
9
|
-
super
|
10
|
-
self.type = type
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module RETS4R
|
2
|
-
class Client
|
3
|
-
# Represents a RETS object (as returned by the get_object) transaction.
|
4
|
-
class DataObject
|
5
|
-
attr_accessor :type, :data
|
6
|
-
|
7
|
-
alias :info :type
|
8
|
-
|
9
|
-
def initialize(type, data)
|
10
|
-
self.type = type
|
11
|
-
self.data = data
|
12
|
-
end
|
13
|
-
|
14
|
-
def success?
|
15
|
-
return true if self.data
|
16
|
-
return false
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'rets4r/client/data'
|
2
|
-
|
3
|
-
module RETS4R
|
4
|
-
class Client
|
5
|
-
# Represents a set of metadata. It is simply an extended Array with type and attributes accessors.
|
6
|
-
class Metadata < Array
|
7
|
-
attr_accessor :type, :attributes
|
8
|
-
|
9
|
-
def initialize(type = false)
|
10
|
-
self.type = type if type
|
11
|
-
self.attributes = {}
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# Parses XML response containing 'COMPACT' data format.
|
2
|
-
|
3
|
-
require 'cgi'
|
4
|
-
|
5
|
-
module RETS4R
|
6
|
-
class Client
|
7
|
-
class CompactDataParser
|
8
|
-
def parse_results(doc)
|
9
|
-
|
10
|
-
delimiter = doc.get_elements('/RETS/DELIMITER')[0] &&
|
11
|
-
doc.get_elements('/RETS/DELIMITER')[0].attributes['value'].to_i.chr
|
12
|
-
columns = doc.get_elements('/RETS/COLUMNS')[0]
|
13
|
-
rows = doc.get_elements('/RETS/DATA')
|
14
|
-
|
15
|
-
parse_data(columns, rows, delimiter)
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse_data(column_element, row_elements, delimiter = "\t")
|
19
|
-
|
20
|
-
column_names = column_element.to_s.split(delimiter)
|
21
|
-
|
22
|
-
result = []
|
23
|
-
|
24
|
-
data = row_elements.each do |data_row|
|
25
|
-
data_row = data_row.text.split(delimiter)
|
26
|
-
|
27
|
-
row_result = {}
|
28
|
-
|
29
|
-
column_names.each_with_index do |col, x|
|
30
|
-
row_result[col] = data_row[x]
|
31
|
-
end
|
32
|
-
|
33
|
-
row_result.reject! { |k,v| k.nil? || k.empty? }
|
34
|
-
|
35
|
-
result << row_result
|
36
|
-
end
|
37
|
-
|
38
|
-
return result
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'nokogiri'
|
3
|
-
module RETS4R
|
4
|
-
class Client
|
5
|
-
class CompactNokogiriParser
|
6
|
-
|
7
|
-
def initialize(io)
|
8
|
-
@doc = CompactDocument.new
|
9
|
-
@parser = Nokogiri::XML::SAX::Parser.new(@doc)
|
10
|
-
@io = io
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_a
|
14
|
-
@parser.parse(@io) if @doc.results.empty?
|
15
|
-
@doc.results
|
16
|
-
end
|
17
|
-
|
18
|
-
def each(&block)
|
19
|
-
@doc.proc = block.to_proc
|
20
|
-
@parser.parse(@io)
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
|
24
|
-
class CompactDocument < Nokogiri::XML::SAX::Document
|
25
|
-
attr_reader :results
|
26
|
-
attr_writer :proc
|
27
|
-
|
28
|
-
def initialize
|
29
|
-
@results = []
|
30
|
-
end
|
31
|
-
def start_element name, attrs = []
|
32
|
-
case name
|
33
|
-
when 'DELIMITER'
|
34
|
-
@delimiter = attrs.last.to_i.chr
|
35
|
-
when 'COLUMNS'
|
36
|
-
@columns_element = true
|
37
|
-
@string = ''
|
38
|
-
when 'DATA'
|
39
|
-
@data_element = true
|
40
|
-
@string = ''
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def end_element name
|
45
|
-
case name
|
46
|
-
when 'COLUMNS'
|
47
|
-
@columns_element = false
|
48
|
-
@columns = @string.split(@delimiter)
|
49
|
-
when 'DATA'
|
50
|
-
@data_element = false
|
51
|
-
handle_row
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def characters string
|
56
|
-
if @columns_element
|
57
|
-
@string << string
|
58
|
-
elsif @data_element
|
59
|
-
@string << string
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
def handle_row
|
65
|
-
data = make_hash
|
66
|
-
if @proc
|
67
|
-
@proc.call(data)
|
68
|
-
else
|
69
|
-
@results << data
|
70
|
-
end
|
71
|
-
end
|
72
|
-
def make_hash
|
73
|
-
@columns.zip(@string.split(@delimiter)).inject({}) do | h,(k,v) |
|
74
|
-
h[k] = v unless k.empty?
|
75
|
-
next h
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
require 'yaml'
|
3
|
-
require 'rets4r/client/parsers/compact'
|
4
|
-
|
5
|
-
module RETS4R
|
6
|
-
class Client
|
7
|
-
class MetadataParser
|
8
|
-
|
9
|
-
TAGS = [ 'METADATA-RESOURCE',
|
10
|
-
'METADATA-CLASS',
|
11
|
-
'METADATA-TABLE',
|
12
|
-
'METADATA-OBJECT',
|
13
|
-
'METADATA-LOOKUP',
|
14
|
-
'METADATA-LOOKUP_TYPE' ]
|
15
|
-
|
16
|
-
def initialize()
|
17
|
-
@parser = RETS4R::Client::CompactDataParser.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def parse_file(file = 'metadata.xml')
|
21
|
-
xml = File.read(file)
|
22
|
-
doc = REXML::Document.new(xml)
|
23
|
-
parse(doc)
|
24
|
-
end
|
25
|
-
|
26
|
-
def parse(doc)
|
27
|
-
|
28
|
-
rets_resources = {}
|
29
|
-
|
30
|
-
doc.get_elements('/RETS/*').each do |elem|
|
31
|
-
|
32
|
-
next unless TAGS.include?(elem.name)
|
33
|
-
|
34
|
-
columns = elem.get_elements('COLUMNS')[0]
|
35
|
-
rows = elem.get_elements('DATA')
|
36
|
-
|
37
|
-
data = @parser.parse_data(columns, rows)
|
38
|
-
|
39
|
-
resource_id = elem.attributes['Resource']
|
40
|
-
|
41
|
-
case elem.name
|
42
|
-
when 'METADATA-RESOURCE'
|
43
|
-
data.each do |resource_info|
|
44
|
-
id = resource_info.delete('ResourceID')
|
45
|
-
rets_resources[id] = resource_info
|
46
|
-
end
|
47
|
-
|
48
|
-
when 'METADATA-CLASS'
|
49
|
-
data.each do |class_info|
|
50
|
-
class_name = class_info.delete('ClassName')
|
51
|
-
rets_resources[resource_id][:classes] ||= {}
|
52
|
-
rets_resources[resource_id][:classes][class_name] = class_info
|
53
|
-
end
|
54
|
-
|
55
|
-
when 'METADATA-TABLE'
|
56
|
-
class_name = elem.attributes['Class']
|
57
|
-
data.each do |table_info|
|
58
|
-
system_name = table_info.delete('SystemName')
|
59
|
-
rets_resources[resource_id][:classes][class_name][:tables] ||= {}
|
60
|
-
rets_resources[resource_id][:classes][class_name][:tables][system_name] = table_info
|
61
|
-
end
|
62
|
-
|
63
|
-
when 'METADATA-OBJECT'
|
64
|
-
data.each do |object_info|
|
65
|
-
object_type = object_info.delete('ObjectType')
|
66
|
-
rets_resources[resource_id][:objects] ||= {}
|
67
|
-
rets_resources[resource_id][:objects][object_type] = object_info
|
68
|
-
end
|
69
|
-
|
70
|
-
when 'METADATA-LOOKUP'
|
71
|
-
data.each do |lookup_info|
|
72
|
-
lookup_name = lookup_info.delete('LookupName')
|
73
|
-
rets_resources[resource_id][:lookups] ||= {}
|
74
|
-
rets_resources[resource_id][:lookups][lookup_name] = lookup_info
|
75
|
-
end
|
76
|
-
|
77
|
-
when 'METADATA-LOOKUP_TYPE'
|
78
|
-
lookup = elem.attributes['Lookup']
|
79
|
-
rets_resources[resource_id][:lookup_types] ||= {}
|
80
|
-
rets_resources[resource_id][:lookup_types][lookup] = {}
|
81
|
-
data.each do |lookup_type_info|
|
82
|
-
value = lookup_type_info.delete('Value')
|
83
|
-
rets_resources[resource_id][:lookup_types][lookup][value] = lookup_type_info
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
rets_resources
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'rets4r/client/transaction'
|
2
|
-
require 'rets4r/client/parsers/compact'
|
3
|
-
require 'rexml/document'
|
4
|
-
|
5
|
-
module RETS4R
|
6
|
-
class Client
|
7
|
-
class ResponseParser
|
8
|
-
def parse_key_value(xml)
|
9
|
-
parse_common(xml) do |doc|
|
10
|
-
parsed = nil
|
11
|
-
first_child = doc.get_elements('/RETS/RETS-RESPONSE')[0] ? doc.get_elements('/RETS/RETS-RESPONSE')[0] : doc.get_elements('/RETS')[0]
|
12
|
-
unless first_child.nil?
|
13
|
-
parsed = {}
|
14
|
-
first_child.text.each do |line|
|
15
|
-
(key, value) = line.strip.split('=')
|
16
|
-
key.strip! if key
|
17
|
-
value.strip! if value
|
18
|
-
parsed[key] = value
|
19
|
-
end
|
20
|
-
else
|
21
|
-
raise 'Response was not a proper RETS XML doc!'
|
22
|
-
end
|
23
|
-
|
24
|
-
if parsed.nil?
|
25
|
-
raise "Response was not valid key/value format"
|
26
|
-
else
|
27
|
-
parsed
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def parse_results(xml, format)
|
33
|
-
parse_common(xml) do |doc|
|
34
|
-
parser = get_parser_by_name(format)
|
35
|
-
parser.parse_results(doc)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def parse_count(xml)
|
40
|
-
parse_common(xml) do |doc|
|
41
|
-
doc.get_elements('/RETS/COUNT')[0].attributes['Records']
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def parse_metadata(xml, format)
|
46
|
-
parse_common(xml) do |doc|
|
47
|
-
return REXML::Document.new(xml)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def parse_object_response(xml)
|
52
|
-
parse_common(xml) do |doc|
|
53
|
-
# XXX
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def parse_common(xml, &block)
|
60
|
-
if xml == ''
|
61
|
-
raise RETSException, 'No transaction body was returned!'
|
62
|
-
end
|
63
|
-
|
64
|
-
doc = REXML::Document.new(xml)
|
65
|
-
|
66
|
-
root = doc.root
|
67
|
-
if root.nil? || root.name != 'RETS'
|
68
|
-
raise "Response had invalid root node. Document was: #{doc.inspect}"
|
69
|
-
end
|
70
|
-
|
71
|
-
transaction = Transaction.new
|
72
|
-
transaction.reply_code = root.attributes['ReplyCode']
|
73
|
-
transaction.reply_text = root.attributes['ReplyText']
|
74
|
-
transaction.maxrows = (doc.get_elements('/RETS/MAXROWS').length > 0)
|
75
|
-
|
76
|
-
|
77
|
-
# XXX: If it turns out we need to parse the response of errors, then this will
|
78
|
-
# need to change.
|
79
|
-
if transaction.reply_code.to_i > 0 && transaction.reply_code.to_i != 20201
|
80
|
-
exception_type = Client::EXCEPTION_TYPES[transaction.reply_code.to_i] || RETSTransactionException
|
81
|
-
raise exception_type, "#{transaction.reply_code} - #{transaction.reply_text}"
|
82
|
-
end
|
83
|
-
|
84
|
-
transaction.response = yield doc
|
85
|
-
return transaction
|
86
|
-
end
|
87
|
-
|
88
|
-
def get_parser_by_name(name)
|
89
|
-
case name
|
90
|
-
when 'COMPACT', 'COMPACT-DECODED'
|
91
|
-
type = RETS4R::Client::CompactDataParser
|
92
|
-
else
|
93
|
-
raise "Invalid format #{name}"
|
94
|
-
end
|
95
|
-
type.new
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module RETS4R
|
2
|
-
class Client
|
3
|
-
class Transaction
|
4
|
-
attr_accessor :reply_code, :reply_text, :response, :metadata,
|
5
|
-
:header, :maxrows, :delimiter, :secondary_response
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
self.maxrows = false
|
9
|
-
self.header = []
|
10
|
-
self.delimiter = ?\t
|
11
|
-
end
|
12
|
-
|
13
|
-
def success?
|
14
|
-
return true if self.reply_code == '0'
|
15
|
-
return false
|
16
|
-
end
|
17
|
-
|
18
|
-
def maxrows?
|
19
|
-
return true if self.maxrows
|
20
|
-
return false
|
21
|
-
end
|
22
|
-
|
23
|
-
def ascii_delimiter
|
24
|
-
self.delimiter.chr
|
25
|
-
end
|
26
|
-
|
27
|
-
# For compatibility with the original library.
|
28
|
-
alias :data :response
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# from ActiveSupport
|
2
|
-
class Array
|
3
|
-
# Extracts options from a set of arguments. Removes and returns the last
|
4
|
-
# element in the array if it's a hash, otherwise returns a blank hash.
|
5
|
-
#
|
6
|
-
# def options(*args)
|
7
|
-
# args.extract_options!
|
8
|
-
# end
|
9
|
-
#
|
10
|
-
# options(1, 2) # => {}
|
11
|
-
# options(1, 2, :a => :b) # => {:a=>:b}
|
12
|
-
def extract_options!
|
13
|
-
last.is_a?(::Hash) ? pop : {}
|
14
|
-
end
|
15
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'rets4r/core_ext/array/extract_options'
|
2
|
-
# from ActiveSupport
|
3
|
-
|
4
|
-
# Extends the class object with class and instance accessors for class attributes,
|
5
|
-
# just like the native attr* accessors for instance attributes.
|
6
|
-
#
|
7
|
-
# class Person
|
8
|
-
# cattr_accessor :hair_colors
|
9
|
-
# end
|
10
|
-
#
|
11
|
-
# Person.hair_colors = [:brown, :black, :blonde, :red]
|
12
|
-
class Class
|
13
|
-
def cattr_reader(*syms)
|
14
|
-
syms.flatten.each do |sym|
|
15
|
-
next if sym.is_a?(Hash)
|
16
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
17
|
-
unless defined? @@#{sym} # unless defined? @@hair_colors
|
18
|
-
@@#{sym} = nil # @@hair_colors = nil
|
19
|
-
end # end
|
20
|
-
#
|
21
|
-
def self.#{sym} # def self.hair_colors
|
22
|
-
@@#{sym} # @@hair_colors
|
23
|
-
end # end
|
24
|
-
#
|
25
|
-
def #{sym} # def hair_colors
|
26
|
-
@@#{sym} # @@hair_colors
|
27
|
-
end # end
|
28
|
-
EOS
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def cattr_writer(*syms)
|
33
|
-
options = syms.extract_options!
|
34
|
-
syms.flatten.each do |sym|
|
35
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
36
|
-
unless defined? @@#{sym} # unless defined? @@hair_colors
|
37
|
-
@@#{sym} = nil # @@hair_colors = nil
|
38
|
-
end # end
|
39
|
-
#
|
40
|
-
def self.#{sym}=(obj) # def self.hair_colors=(obj)
|
41
|
-
@@#{sym} = obj # @@hair_colors = obj
|
42
|
-
end # end
|
43
|
-
#
|
44
|
-
#{" #
|
45
|
-
def #{sym}=(obj) # def hair_colors=(obj)
|
46
|
-
@@#{sym} = obj # @@hair_colors = obj
|
47
|
-
end # end
|
48
|
-
" unless options[:instance_writer] == false } # # instance writer above is generated unless options[:instance_writer] == false
|
49
|
-
EOS
|
50
|
-
self.send("#{sym}=", yield) if block_given?
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def cattr_accessor(*syms, &blk)
|
55
|
-
cattr_reader(*syms)
|
56
|
-
cattr_writer(*syms, &blk)
|
57
|
-
end
|
58
|
-
end
|