tourets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rvmrc
7
+ .rspec
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tourets.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jeremy Woertink & Justin Mitchell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,97 @@
1
+ # TouRETS
2
+
3
+ The name came from a play on Tourette's and RETS. Because when you work with RETS you feel like you have Tourette's.
4
+ The goal of this gem is to make a really clean and familiar API for connecting to a RETS server. This gem was designed to be used with rails, so it takes a lot of the API that rails uses.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'tourets', :github => 'jwoertink/tourets'
11
+
12
+ Add a rets_config.yml to the config directory of your rails app
13
+
14
+ ```yaml
15
+ -
16
+ mls: 'GLVAR'
17
+ url: 'http://las.rets.interealty.com/Login.asmx/Login'
18
+ username: 'user'
19
+ password: 'secret'
20
+ rets_version: '1.8'
21
+ auth_mode: :digest
22
+ useragent:
23
+ name: 'some_user_connector'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install tourets
33
+
34
+ ## Usage
35
+ (since this is still new, this usage may change often)
36
+
37
+ ```ruby
38
+ begin
39
+ TouRETS.establish_connection('GLVAR')
40
+ # Get a list of properties with 3 bedrooms and 2 bathrooms
41
+ @properties = TouRETS::Property.where(:bedrooms => 3, :bathrooms => 2)
42
+ # Grab all the photos for the first property
43
+ @photos = @properties.first.photos
44
+ # Iterate through all those photos, save them into tempfiles, and then do stuff?
45
+ @photos.each do |photo|
46
+ begin
47
+ tmp = Tempfile.new(photo.filename)
48
+ tmp.write(photo.image)
49
+ # you have an actual photo now. Maybe push to S3?
50
+ ensure
51
+ tmp.close
52
+ tmp.unlink
53
+ end
54
+ end
55
+ ensure
56
+ TouRETS.close_connection
57
+ end
58
+ ```
59
+
60
+ Before doing anything, you must make your first initial connection to your MLS server.
61
+ ```ruby
62
+ if TouRETS.current_connection?
63
+ # Get the sysid for the last property in that instance array
64
+ property_id = @properties.last.id
65
+ puts property_id #=> 1234567
66
+ # Grab the second picture for that property
67
+ picture = TouRETS::Photo.find(property_id, :id => 2)
68
+ puts picture.content_type #=> image/jpeg
69
+ puts picture.filename #=> 1234567-2.jpg
70
+ puts picture.id #=> 2
71
+ # This returns the binary string data that gets written to a file
72
+ puts picture.image.class #=> String
73
+ end
74
+ ```
75
+
76
+ ## ruby-rets
77
+ This gem relies heavily on the work done by Zachary Anker (zanker) with the [ruby-rets](https://github.com/Placester/ruby-rets) gem.
78
+ There is a `TouRETS::Search#find` class which just makes a direct call to the `RETS::Base::Core#search`. This gives you the option to still use
79
+ that gem inside of this one.
80
+
81
+ ## TODO (in no particular order)
82
+ 1. Add in other Objects like VRImage, Thumbnail, Map, Video, Audio
83
+ 2. Add in other Resources like Agent, Office, LotsAndLand
84
+ 3. CLEAN CODE!!!!!
85
+ 4. Add in limits, and selects to searches
86
+ 5. TEST TEST TEST TEST
87
+ 6. Add some passing specs.
88
+ 7. Document the hell out of this thing
89
+
90
+
91
+ ## Contributing
92
+
93
+ 1. Fork it
94
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
95
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
96
+ 4. Push to the branch (`git push origin my-new-feature`)
97
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,61 @@
1
+ require 'ruby-rets'
2
+ require 'tourets/rails'
3
+ require 'tourets/utilities'
4
+ require 'tourets/exceptions'
5
+ require 'tourets/extensions/hash' # This should go away after Rails 4.0
6
+ require 'tourets/search'
7
+ require 'tourets/photo'
8
+ require 'tourets/property'
9
+
10
+ module TouRETS
11
+ include Utilities
12
+
13
+ class << self
14
+ attr_accessor :current_connection
15
+
16
+ # This will take the specific MLS you want to connect to
17
+ # There must be a rets_config.yml file in the :rails_root/config directory
18
+ #
19
+ def establish_connection(mls)
20
+ config_file = File.join(app_root, 'config', 'rets_config.yml')
21
+ if File.exists?(config_file)
22
+ connections = YAML.load_file(config_file)
23
+ conn = connections.select { |conn| conn['mls'] == mls }.first
24
+ if conn.nil?
25
+ raise ConfigurationError, "Missing or incorrect MLS key `#{mls}`."
26
+ else
27
+ conn.recursive_symbolize_keys!
28
+ conn.delete(:mls)
29
+ self.current_connection = RETS::Client.login(conn)
30
+ end
31
+ else
32
+ raise ConfigurationError, "Couldn't find Config File in #{config_file}."
33
+ end
34
+ end
35
+
36
+ # Closes the current connection to the RETS server
37
+ def close_connection
38
+ current_connection.logout if current_connection?
39
+ current_connection = nil
40
+ end
41
+
42
+ def ensure_connected!
43
+ raise ConnectionError, "You must establish a connection first." unless current_connection?
44
+ end
45
+
46
+ def current_connection?
47
+ !current_connection.nil?
48
+ end
49
+
50
+ # The root of the application using this gem
51
+ def app_root
52
+ if defined?(Rails)
53
+ ::Rails.root
54
+ else
55
+ Dir.pwd
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,7 @@
1
+ module TouRETS
2
+
3
+ class ConfigurationError < StandardError; end
4
+
5
+ class ConnectionError < StandardError; end
6
+
7
+ end
@@ -0,0 +1,20 @@
1
+ # This is only a temporary fix until it's patched in Rails
2
+ class Hash
3
+
4
+ def recursive_symbolize_keys!
5
+ symbolize_keys!
6
+
7
+ values.each{|h| h.recursive_symbolize_keys! if h.is_a?(Hash)}
8
+ values.select{|v| v.is_a?(Array)}.flatten.each{|h| h.recursive_symbolize_keys! if h.is_a?(Hash)}
9
+ self
10
+ end
11
+
12
+ #In case for some reason this isn't picked up from Rails
13
+ def symbolize_keys!
14
+ keys.each do |key|
15
+ self[(key.to_sym rescue key) || key] = delete(key)
16
+ end
17
+ self
18
+ end
19
+
20
+ end
@@ -0,0 +1,53 @@
1
+ module TouRETS
2
+ class Photo
3
+
4
+ class << self
5
+
6
+ # Find the photo
7
+ # Use find("1234", :id => 1) to find the photo with ID 1 in the 1234 group
8
+ # Default it to return all of the photos.
9
+ def find(sysid, opts={})
10
+ limit = opts[:id] || "*"
11
+ [].tap do |photos|
12
+ TouRETS.current_connection.get_object(:resource => opts[:resource], :type => :Photo, :location => false, :id => "#{sysid}:#{limit}") do |headers, content|
13
+ photos << new(headers, content)
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ attr_accessor :id, :resource_id, :content_type, :content
21
+
22
+ # id is the ID of the photo
23
+ # resource_id is the ID of the resource it belongs to. Properties will probably be sysid everytime
24
+ # content_type is the Image content_type
25
+ # content is the Binary string that can be written to a file to display the image.
26
+ def initialize(headers, content)
27
+ self.id = headers["object-id"]
28
+ self.resource_id = headers["content-id"]
29
+ self.content_type = headers["content-type"]
30
+ self.content = content
31
+ end
32
+
33
+ # Use this method to get the binary string to write to a file.
34
+ # Sometimes the string will contin ASCII-8BIT characters.
35
+ # Forcing to UTF-8 will make it write to a file easier.
36
+ def image
37
+ content.to_s.force_encoding("UTF-8")
38
+ end
39
+
40
+ # Returns a filename based on the resource_id and id of the photo
41
+ # should have proper extension on it.
42
+ def filename
43
+ ext = case content_type
44
+ when /jpeg$/, /jpg$/ then "jpg"
45
+ when /png$/ then "png"
46
+ when /gif$/ then "gif"
47
+ else "jpg"
48
+ end
49
+ "#{resource_id}-#{id}.#{ext}"
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,84 @@
1
+ module TouRETS
2
+ class Property
3
+ include Utilities
4
+ extend Utilities
5
+
6
+ SEARCH_QUERY_DEFAULTS = {:active_properties => "ER,EA,C", :idx_display => "Y", :internet_display => "Y"}
7
+ # This class searches for ResidentialProperty, Condo, SingleFamily, Rental
8
+ # Some MLS use "1", some use :RES... Will need to decide which way is to be used.
9
+ SEARCH_CONFIG_DEFAULTS = {:search_type => :Property, :class => "1"}
10
+
11
+ class << self
12
+
13
+ # Returns an array of all of the properties
14
+ # Property.all
15
+ def all
16
+ where
17
+ end
18
+
19
+ # Returns an array of property results.
20
+ # Property.where(:bedrooms => 7, :bathrooms => 4, :list_price => 200000..300000)
21
+ # Property.where(:property_type => {:not => ['CONDO', 'TOWNHOME']}, :area => {:or => ['South West', 'North West']})
22
+ # Property.where(:area => ['South West', 'North West']) # This is like 'AND'
23
+ def where(search_params = {})
24
+ TouRETS.ensure_connected!
25
+ [].tap do |properties|
26
+ search_params = map_search_params(SEARCH_QUERY_DEFAULTS.merge(search_params))
27
+ search_config = SEARCH_CONFIG_DEFAULTS.merge({:query => hash_to_rets_query_string(search_params)})
28
+ Search.find(search_config) do |property|
29
+ properties << self.new(property)
30
+ end
31
+ end
32
+ end
33
+
34
+ # # Propert.where(:bedrooms => 3).limit(10) #not implemented
35
+ # def limit(limit_number = 5000)
36
+ # SEARCH_CONFIG_DEFAULTS.merge!(:limit => limit_number)
37
+ # self
38
+ # end
39
+ #
40
+ # # Property.where(:bedrooms => 3).count #not implemented
41
+ # def count
42
+ # SEARCH_CONFIG_DEFAULTS.merge!(:count_mode => :only)
43
+ # self
44
+ # end
45
+ #
46
+ # # Property.select(['SystemName', 'LongName']).where(:bedrooms => 3) #not implemented
47
+ # # select is to limit which fields actually get returned. This could help with mapping
48
+ # def select(fields=[])
49
+ # {:select => fields}
50
+ # self
51
+ # end
52
+
53
+ end
54
+
55
+ attr_accessor :attributes
56
+
57
+ def initialize(args = {})
58
+ self.attributes = args
59
+ end
60
+
61
+ # Return an array of the photo objects that belong to a particular property
62
+ def photos
63
+ @photos ||= grab_photos
64
+ end
65
+
66
+ def method_missing(method_name, *args, &block)
67
+ val = attributes[key_map[method_name.to_sym]]
68
+ if val.nil?
69
+ super
70
+ else
71
+ return val
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def grab_photos
78
+ [].tap do |pics|
79
+ pics << TouRETS::Photo.find(attributes['sysid'], :resource => :Property)
80
+ end.flatten
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails'
2
+ require 'tourets/rails/engine'
3
+ require 'tourets/rails/railtie'
4
+ require 'tourets/rails/version'
5
+
6
+ module TouRETS
7
+ module Rails
8
+
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module TouRETS
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module TouRETS
3
+ module Rails
4
+ class Railtie < ::Rails::Railtie
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module TouRETS
2
+ module Rails
3
+ VERSION = "0.1.0"
4
+
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ module TouRETS
2
+
3
+ class Search
4
+
5
+ class << self
6
+
7
+ # This works as a raw search. This give the developer a chance
8
+ # to customize how they want to search.
9
+ def find(search_params = {}, &block)
10
+ raise ArgumentError, "No block passed" unless block_given?
11
+ TouRETS.ensure_connected!
12
+ TouRETS.current_connection.search(search_params, &block)
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,138 @@
1
+ module TouRETS
2
+ module Utilities
3
+
4
+ # Convert a key value pair into a RETS formatted query string.
5
+ # TODO: Take values that are arrays, ranges, or hashes, and convert those properly
6
+ def hash_to_rets_query_string(hash)
7
+ [].tap do |str|
8
+ hash.each_pair do |k,v|
9
+ val = value_map(v)
10
+ str << "(#{k.to_s.camelize}=#{val})"
11
+ end
12
+ end.join(',')
13
+ end
14
+
15
+ # This takes a hash of search parameters, and modifies
16
+ # the hash to have the correct key types for the current RETS server
17
+ def map_search_params(search_params)
18
+ Hash[search_params.map {|k, v| [key_map[k], v] }]
19
+ end
20
+
21
+ # Giant Hash.
22
+ # TODO: OPTIMIZE!!!! ZOMG! O_o
23
+ # Maybe break this into a YAML file that will pick which keymap to use based on the current_connection?
24
+ # I'm thinking maybe like a dictionary lookup. Figure out what each RETS server uses.
25
+ # Also good to note that there are different data types, but they all are strings.
26
+ # We could figure out a way to convert to Integer, or DateTime objects, etc... depending.
27
+ def key_map
28
+ {
29
+ :id => "sysid", #String
30
+ :property_type => "1", #String
31
+ :acreage => "2", #Float
32
+ :zip_code => "10", #String
33
+ :address => "13", #String
34
+ :partial_flag => "17", #String
35
+ :close_date => "25", #DateTime
36
+ :agent_name => "26", #String
37
+ :annual_property_tax => "28", #Integer
38
+ :has_dishwasher => "30", #Boolean
39
+ :has_disposal => "31", #Boolean
40
+ :has_refrigerator => "33", #Boolean
41
+ :dryer_hookup => "34", #String
42
+ :area => "37", #String
43
+ :association_fee => "39", #Integer
44
+ #1st Encumbr Assumption Desc => "43" # Like the mortgage...
45
+ :three_quarter_baths => "60", #Integer
46
+ :bathrooms => "61", #Integer
47
+ :half_baths => "62", #Integer
48
+ :total_baths => "63", #Integer
49
+ :downstairs_bath_desc => "63",#String
50
+ :bedrooms => "68", #Integer
51
+ :built_desc => "72", #String
52
+ :carport_desc => "73", #String
53
+ :carports => "74", #Integer
54
+ :comp_days_on_market => "81", #Integer (this is nil sometimes)
55
+ :contingency_desc => "84", #String
56
+ :contract_date => "85", #DateTime
57
+ :cooling_fuel_desc => "86", #String
58
+ :county => "87", #String
59
+ :second_bed_dim => "89", #String
60
+ :third_bed_dim => "90", #String
61
+ :fourth_bed_dim => "91", #String
62
+ :dining_room_dim => "92", #String
63
+ :family_room_dim => "93", #String
64
+ :fifth_bed_dim => "94", #String
65
+ :living_room_dim => "95", #String
66
+ :master_bed_dim => "96", #String
67
+ :fifth_bed_desc => "97", #String
68
+ :days_on_market => "101", #Integer
69
+ :entry_date => "104", #DateTime
70
+ :fence => "112", #String
71
+ :fireplaces => "113", #Integer
72
+ :converted_garage? => "120", #Boolean
73
+ :garages => "122", #Integer
74
+ :ground_mounted? => "125", #Boolean
75
+ :images => "129", #Integer
76
+ :internet_display => "130", #Boolean
77
+ :land_use => "132", #Integer
78
+ :last_transaction_code => "134", #String
79
+ :last_transaction_at => "135",#DateTime
80
+ :list_office_code => "137", #String
81
+ :listed_on => "138", #DateTime
82
+ :agentcode => "143", #String
83
+ :list_price => "144", #Float
84
+ :agent_member_id => "145", #String
85
+ :lot_sqft => "154", #Integer
86
+ :community => "155", #String
87
+ :listing_number => "163", #String
88
+ :occupancy_desc => "170", #String
89
+ :listing_office => "171", #String
90
+ :listing_office_phone => "172", #String
91
+ :original_list_price => "173",#Float
92
+ :parcel_number => "176", #String
93
+ :photo_instructions => "182", #String
94
+ :pools => "184", #Integer
95
+ :property_condition => "202", #String
96
+ :has_pool => "203", #Boolean
97
+ :record_deleted_at => "205", #DateTime
98
+ :record_deleted => "207", #Boolean
99
+ :buyer_broker => "211", #String
100
+ :elementary_school_2 => "213",#String
101
+ :highschool => "214", #String
102
+ :middle_school => "215", #String
103
+ :year_round_school => "216", #String
104
+ :buyer_agentcode => "218", #String
105
+ :sewer => "219", #String
106
+ # #Loft => "231", #Integer
107
+ :has_spa => "236", #Boolean
108
+ :active_properties => "242",
109
+ :idx_display => "1809",
110
+ :sqft => "2361"
111
+ }
112
+ end
113
+
114
+ # Take values like true and false, convert them to "Y" or "N". make collections into joint strings.
115
+ def value_map(value)
116
+ v = case value.class
117
+ when Array
118
+ value.join(',')
119
+ when Range
120
+ "#{value.first}-#{value.last}"
121
+ when Hash
122
+ if value.has_key?(:or)
123
+ "|#{value[:or].join(',')}"
124
+ elsif value.has_key?(:not)
125
+ "~#{value[:not].join(',')}"
126
+ end
127
+ when TrueClass
128
+ "Y" # TODO: figure out if this should be Y or Yes
129
+ when FalseClass
130
+ "N" # TODO: figure out if this should be N or No
131
+ else
132
+ value
133
+ end
134
+ v
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,30 @@
1
+ # NOTE: This class is not really implemented yet.
2
+
3
+ module TouRETS
4
+
5
+ # VRImage is a multiple-view, possibly-interactive image related to the :resource
6
+ class VRImage
7
+
8
+ class << self
9
+
10
+ # Find the vrimage
11
+ # Use find("1234", :id => 1) to find the photo with ID 1 in the 1234 group
12
+ # Default it to return all of the photos.
13
+ def find(sysid, opts={})
14
+ limit = opts[:id] || "*"
15
+ [].tap do |photos|
16
+ TouRETS.current_connection.get_object(:resource => opts[:resource], :type => :VRImage, :location => false, :id => "#{sysid}:#{limit}") do |headers, content|
17
+ photos << new(headers, content)
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+
25
+ def initialize(headers, content)
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/tourets/rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Jeremy Woertink", "Justin Mitchell"]
6
+ gem.email = ["jeremywoertink@gmail.com", "jmitchell4140@gmail.com"]
7
+ gem.description = "TouRETS is a rails gem used to interface with multiple RETS using the ruby-rets gem"
8
+ gem.summary = "Use RETS with a LOT less hassle"
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "tourets"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = TouRETS::Rails::VERSION
17
+
18
+ gem.add_dependency('ruby-rets', '2.0.5')
19
+ gem.add_dependency('railties', '>= 3.1')
20
+ gem.add_development_dependency('rspec')
21
+ gem.add_development_dependency('rails', '>= 3.1')
22
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tourets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Woertink
9
+ - Justin Mitchell
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-11-16 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruby-rets
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - '='
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.5
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - '='
29
+ - !ruby/object:Gem::Version
30
+ version: 2.0.5
31
+ - !ruby/object:Gem::Dependency
32
+ name: railties
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '3.1'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '3.1'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rails
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '3.1'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '3.1'
79
+ description: TouRETS is a rails gem used to interface with multiple RETS using the
80
+ ruby-rets gem
81
+ email:
82
+ - jeremywoertink@gmail.com
83
+ - jmitchell4140@gmail.com
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/tourets.rb
94
+ - lib/tourets/exceptions.rb
95
+ - lib/tourets/extensions/hash.rb
96
+ - lib/tourets/photo.rb
97
+ - lib/tourets/property.rb
98
+ - lib/tourets/rails.rb
99
+ - lib/tourets/rails/engine.rb
100
+ - lib/tourets/rails/railtie.rb
101
+ - lib/tourets/rails/version.rb
102
+ - lib/tourets/search.rb
103
+ - lib/tourets/utilities.rb
104
+ - lib/tourets/vrimage.rb
105
+ - tourets.gemspec
106
+ homepage: ''
107
+ licenses: []
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ segments:
119
+ - 0
120
+ hash: 3840694011043471350
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ segments:
128
+ - 0
129
+ hash: 3840694011043471350
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.24
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Use RETS with a LOT less hassle
136
+ test_files: []