rentjuicer 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,6 +1,177 @@
1
1
  = rentjuicer
2
2
 
3
- Description goes here.
3
+ Rentjuicer is a ruby gem that wraps the rentjucier.com api for listings, neighborhoods and adding leads. Rentjuicer is built on top of HTTParty.
4
+
5
+ Rentjuicer requires access to rentjuice.com's api through an Rentjuice api key so make sure you have acquired a key from Rentjuice before starting with this gem.
6
+
7
+ API documentation is here: http://api.rentjuice.com/documentation/RentJuice_API.pdf
8
+
9
+
10
+ == Installation
11
+
12
+ gem install rentjuicer
13
+
14
+ In a rails 2.3.x app
15
+
16
+ config.gem 'rentjuicer'
17
+
18
+
19
+ == Usage
20
+
21
+ Responses from the api come back as Hashie::Rash objects, each response will be described below
22
+
23
+ For documentation on Hashie::Rash see the following: http://github.com/tcocca/rash
24
+
25
+ Basically HTTParty parses the JSON response into a hash, which is then converted into a Hashie::Rash. This takes all hash keys and converts camelCased keys to underscored keys (eg: 'camelCase' => 'camel_case') and then makes those keys accessble as methods.
26
+
27
+ So all responses create a :body method to access the data:
28
+
29
+ @results.body.neighbhoroods # => array of Hashie::Rash objects
30
+
31
+ Look at the JSON being returned and all of those keys are accessible as methods on the :body method for your Rentjuicer::Response method.
32
+
33
+ Rentjuicer::Response also implements some method_missing so any methods on response.body can be accessed directly on response, eg:
34
+
35
+ @results.neighborhoods == @results.body.neighborhoods
36
+
37
+ In the rest of the README I will be accessing the methods off of response as I think it is cleaner to use and read.
38
+
39
+
40
+ === Creating a Rentjuicer Client
41
+
42
+ A rentjuicer client is necessary as this is the object that makes requests, each of classes that interacts with the api requires a rentjuicer client to be passed in to the new call.
43
+
44
+ @rentjuicer = Rentjuicer::Client.new('some_api_key')
45
+
46
+
47
+ === Getting a list of your neighborhoods
48
+
49
+ To get a list of your neighborhoods in rentjuice you can access the neighborhoods resource and call find_all
50
+
51
+ @neighborhoods = Rentjuicer::Neighborhoods.new(@rentjuicer) # where @rentjuicer is the client created above
52
+ @response = @neighborhoods.find_all # returns a Rentjuicer::Response object
53
+
54
+ @response.neighborhoods contains an array of Rentjuice neighborhood objects in Hashie::Rash format
55
+
56
+ if the request is invalid a Rentjuicer::Error exception will be raised
57
+
58
+
59
+ === Adding a lead to your account
60
+
61
+ To add a lead to your Rentjuice lead management system there are two methods, create and create!
62
+ create will not raise an error but the response will not be successful if there is an error.
63
+ create! will raise a Rentjuicer::Error if there is an error.
64
+
65
+ @lead = Rentjuicer::Lead.new(@rentjuicer)
66
+ @result = @lead.create('John Smith')
67
+ @result.success? # => true
68
+
69
+ @result = @lead.create!('John Smith') # raises an error if the create fails
70
+
71
+ create and create! take a mandatory "name" paramater and also take an optional hash of parameters as specified in the API documentation. All optional params are passed straight through to the api so keys and values should be passed in exactly as the documentation states.
72
+
73
+
74
+ === Searching for listings
75
+
76
+ There are 5 methods to the Rentjuicer::Listings class in two "groups"
77
+
78
+ ==== The first group will return Rentjuicer::Listings::SearchResponse responses
79
+
80
+ :search - searches for listings based on the params passed in, if no params are passed in it will return all properties
81
+ :featured - same as search above (takes a params hash) but merges in the :featured => 1 param so that it will only return featured listings
82
+
83
+ Search and Featured default to 20 listings per page of the request
84
+
85
+ These methods all return a Rentjuicer::Listings::SearchResults response
86
+
87
+ @listings = Rentjuicer::Listings.new(@rentjuicer)
88
+ @results = @listings.search(:neighborhoods => 'Boston') # => all listings in Boston
89
+ @results = @listings.featured(:max_rent => '2000') # => all featured listings under 2000
90
+ @results = @listings.find_by_id(18330) # => returns listing 18330 as the only property in @results.properties if that property is found
91
+
92
+ ==== Rentjuicer::Listings::SearchResponse
93
+
94
+ inherits from Rentjuicer::Response so @results.body will return a Hashie::Rash of the json that is returned from the api call
95
+
96
+ method_missing applies here as well so any methods on @results.body can be called on @results
97
+
98
+ It also adds 2 methods
99
+
100
+ :properties - this method returns an array of Rentjuicer::Listing objects (see below)
101
+ :paginator - returns a WillPaginate::Collection object created from the response where the pager cycles the :properties array
102
+
103
+ @results.properties # => an array of Rentjuicer::Listing objects
104
+ @results.paginator.total_entries # => total number of properties
105
+ @results.paginator # => the @results.properties objects
106
+
107
+ ==== Rentjuicer::Listing
108
+
109
+ Rentjuicer::Listing creates an object from a hash (or in our case our Hashie::Rash object) by converting the hash keys to instance variables who's value is the key's value from the hash, then it creates methods that return those instance variables.
110
+
111
+ @results.properties is just an array of these Rentjuicer::Listing objects that are converted from @results.listings
112
+
113
+ so @results.listings.first.neighborhoods == @results.properties.first.neighborhoods
114
+
115
+ Where this comes in handy though is that now that it is a class, we can extend it to add more methods which is exactly what we have done
116
+
117
+ a Rentjuicer::Listing object responds to the following methods:
118
+
119
+ :id - returns the rentjuice_id for convenience
120
+ :sorted_photos - returns the self.photos sorted by the :sort_order key passed back through the api
121
+ :main_pic - this is not always the first photo in the sorted list, in fact there is a specific key in the photo hash to designate the main photo, so main_pic returns the photo object that is designated
122
+ :thumb_pic - returns the url for the main_pic thumbnail
123
+ :first_pic - returns the url for the main_pic fullsize photo
124
+ :neighborhood_name - returns the first name in the neighborhoods hash
125
+
126
+ Also, we have added another method :similar_listings which takes a Rentjuicer::Client object and does a search call
127
+
128
+ @results.properties.first.similar_listings(@rentjuicer)
129
+
130
+ This method performs a search and returns an array for Rentjuicer::Listing objects based on the following criteria
131
+
132
+ :min_rent => self.rent.to_i * 0.9,
133
+ :max_rent => self.rent.to_i * 1.1,
134
+ :min_beds => ((self.bedrooms.to_i - 1) <= 0 ? 0 : (self.bedrooms.to_i - 1)),
135
+ :max_beds => self.bedrooms.to_i + 1,
136
+ :min_baths => ((self.bathrooms.to_i - 1) <= 0 ? 0 : (self.bathrooms.to_i - 1)),
137
+ :max_baths => self.bathrooms.to_i + 1,
138
+ :neighborhoods => self.neighborhood_name
139
+
140
+ You can also pass a limit to the similar_listings method, the default is 6 properties (max) returned
141
+
142
+ @results.properties.first.similar_listings(@rentjuicer, 10) # returns max 10 similar listings
143
+
144
+ ===== Extending Rentjuicer::Listing
145
+ Another benefit to this Rentjuicer::Listing class is that in your app you can open the class again and add more methods if you wish. For example create a file: RAILS_ROOT/lib/rentjuicer_extensions.rb with the following:
146
+
147
+ module Rentjuicer
148
+ class Listing
149
+
150
+ def neighborhood_list
151
+ self.neighborhoods.join(', ')
152
+ end
153
+ end
154
+ end
155
+
156
+ and add require 'rentjuicer_extensions' to your config/environment.rb file.
157
+
158
+ Now you can call @results.properties.first.neighborhood_list to get a nice comma separated list of neighborhood names.
159
+ This class allows you to create any methods you want on a listing.
160
+
161
+ === The second group returns Rentjuicer::Listing responses
162
+
163
+ :find_by_id - takes a rentjuice_id for a listing and returns a Rentjuicer::Listing if the property is found or nil if it is not found
164
+ @property = @listings.find_by_id(18830) # returns either nil or a Rentjuicer::Listing
165
+
166
+ These methods just return a Rentjuicer::Listing or an array of Rentjuicer::Listing objects.
167
+ These methods work by making subsequent calls to go through the pagination of the results for you and compaction each request into a single array. Use these methods only when absolutely necessary as they are expensive to use as they will make repeated api calls through the entire set of pages, so if there are 20 listings per page and 571 pages, this will make 29 api requests which is obviously quite time consuming.
168
+
169
+ :find_all - take a hash of search params (same as :search above) and returns every result on every page of the response in an array
170
+ :find_all_by_ids - takes a comma separated string of rentjuice_ids and returns every listing in an array
171
+
172
+ @results = @listings.find_all(:neighborhoods => 'Boston') # returns an array of every listing in Boston in a single array - no need for pagination
173
+ @results = @listings.find_all_by_ids('200306,200221,200214,200121,199646,198560,197542,197540,197538) # returns an array of all of those listings that can be found
174
+
4
175
 
5
176
  == Note on Patches/Pull Requests
6
177
 
data/Rakefile CHANGED
@@ -11,8 +11,8 @@ begin
11
11
  gem.homepage = "http://github.com/tcocca/rentjuicer"
12
12
  gem.authors = ["tcocca"]
13
13
  gem.add_dependency "httparty", ">= 0.6.1"
14
- gem.add_dependency "hashie", ">= 0.3.1"
15
- gem.add_dependency "rash", ">= 0.1.1"
14
+ gem.add_dependency "hashie", ">= 0.4.0"
15
+ gem.add_dependency "rash", ">= 0.2.0"
16
16
  gem.add_dependency "will_paginate", ">= 2.3.4"
17
17
  gem.add_development_dependency "rspec", ">= 1.2.9"
18
18
  gem.add_development_dependency "webmock", ">= 1.3.4"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
@@ -8,10 +8,6 @@ module Rentjuicer
8
8
  self.resource = "/listings.json"
9
9
  end
10
10
 
11
- def find_by_id(listing_id)
12
- SearchResponse.new(self.client.class.get(resource, :query => {:rentjuice_id => listing_id}))
13
- end
14
-
15
11
  def search(params = {})
16
12
  limit = params[:limit] || 20
17
13
  params[:order_by] ||= "rent"
@@ -24,6 +20,11 @@ module Rentjuicer
24
20
  search(params)
25
21
  end
26
22
 
23
+ def find_by_id(listing_id)
24
+ response = SearchResponse.new(self.client.class.get(resource, :query => {:rentjuice_id => listing_id}))
25
+ (response.success? && response.properties.size > 0) ? response.properties.first : nil
26
+ end
27
+
27
28
  def find_all(params = {})
28
29
  per_page = params[:limit] || 20
29
30
  all_listings = []
@@ -63,9 +64,9 @@ module Rentjuicer
63
64
  end
64
65
 
65
66
  def properties
66
- return [] if @body.listings.blank?
67
+ return [] if self.body.listings.blank?
67
68
  props = []
68
- @body.listings.each do |listing|
69
+ self.body.listings.each do |listing|
69
70
  props << Rentjuicer::Listing.new(listing)
70
71
  end
71
72
  props
@@ -74,9 +75,9 @@ module Rentjuicer
74
75
  def paginator
75
76
  paginator_cache if paginator_cache
76
77
  self.paginator_cache = WillPaginate::Collection.create(
77
- @body.page,
78
+ self.body.page,
78
79
  @limit,
79
- (@body.total_count ? @body.total_count : properties.size)) do |pager|
80
+ (self.body.total_count ? self.body.total_count : properties.size)) do |pager|
80
81
  pager.replace properties
81
82
  end
82
83
  end
@@ -4,12 +4,20 @@ module Rentjuicer
4
4
  attr_accessor :body
5
5
 
6
6
  def initialize(response, raise_error = true)
7
- @body = rash_response(response)
8
- raise Error.new(@body.code, @body.message) if !success? && raise_error
7
+ rash_response(response)
8
+ raise Error.new(self.body.code, self.body.message) if !success? && raise_error
9
9
  end
10
10
 
11
11
  def success?
12
- @body.status == "ok"
12
+ self.body.status == "ok"
13
+ end
14
+
15
+ def method_missing(method_name, *args)
16
+ if self.body.respond_to?(method_name)
17
+ self.body.send(method_name)
18
+ else
19
+ super
20
+ end
13
21
  end
14
22
 
15
23
  private
data/rentjuicer.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rentjuicer}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["tcocca"]
@@ -52,6 +52,7 @@ Gem::Specification.new do |s|
52
52
  "spec/responses/lead_error.json",
53
53
  "spec/responses/listings.json",
54
54
  "spec/responses/neighborhoods.json",
55
+ "spec/responses/no_listings.json",
55
56
  "spec/spec.opts",
56
57
  "spec/spec_helper.rb",
57
58
  "spec/support/listing_helper.rb",
@@ -81,23 +82,23 @@ Gem::Specification.new do |s|
81
82
 
82
83
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
83
84
  s.add_runtime_dependency(%q<httparty>, [">= 0.6.1"])
84
- s.add_runtime_dependency(%q<hashie>, [">= 0.3.1"])
85
- s.add_runtime_dependency(%q<rash>, [">= 0.1.1"])
85
+ s.add_runtime_dependency(%q<hashie>, [">= 0.4.0"])
86
+ s.add_runtime_dependency(%q<rash>, [">= 0.2.0"])
86
87
  s.add_runtime_dependency(%q<will_paginate>, [">= 2.3.4"])
87
88
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
88
89
  s.add_development_dependency(%q<webmock>, [">= 1.3.4"])
89
90
  else
90
91
  s.add_dependency(%q<httparty>, [">= 0.6.1"])
91
- s.add_dependency(%q<hashie>, [">= 0.3.1"])
92
- s.add_dependency(%q<rash>, [">= 0.1.1"])
92
+ s.add_dependency(%q<hashie>, [">= 0.4.0"])
93
+ s.add_dependency(%q<rash>, [">= 0.2.0"])
93
94
  s.add_dependency(%q<will_paginate>, [">= 2.3.4"])
94
95
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
95
96
  s.add_dependency(%q<webmock>, [">= 1.3.4"])
96
97
  end
97
98
  else
98
99
  s.add_dependency(%q<httparty>, [">= 0.6.1"])
99
- s.add_dependency(%q<hashie>, [">= 0.3.1"])
100
- s.add_dependency(%q<rash>, [">= 0.1.1"])
100
+ s.add_dependency(%q<hashie>, [">= 0.4.0"])
101
+ s.add_dependency(%q<rash>, [">= 0.2.0"])
101
102
  s.add_dependency(%q<will_paginate>, [">= 2.3.4"])
102
103
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
103
104
  s.add_dependency(%q<webmock>, [">= 1.3.4"])
@@ -43,15 +43,21 @@ describe Rentjuicer::Listing do
43
43
  mock_get('/listings.json', 'find_by_id.json', {
44
44
  :rentjuice_id => "200306"
45
45
  })
46
- @result = @listings.find_by_id(200306)
46
+ @listing = @listings.find_by_id(200306)
47
47
  end
48
48
 
49
- it { @result.should be_kind_of(Rentjuicer::Listings::SearchResponse) }
50
- it { @result.success?.should be_true }
51
-
52
- it "should return no more than 1 response" do
53
- @result.properties.should have_at_most(1).listings
49
+ it { @listing.should be_kind_of(Rentjuicer::Listing) }
50
+ end
51
+
52
+ context "find_by_id missing" do
53
+ before do
54
+ mock_get('/listings.json', 'no_listings.json', {
55
+ :rentjuice_id => "1"
56
+ })
57
+ @listing = @listings.find_by_id(1)
54
58
  end
59
+
60
+ it { @listing.should be_nil }
55
61
  end
56
62
 
57
63
  context "featured" do
@@ -48,4 +48,27 @@ describe Rentjuicer::Response do
48
48
  end
49
49
  end
50
50
 
51
+ context "method missing" do
52
+ before do
53
+ @rentjuicer = new_rentjuicer
54
+ @listings = Rentjuicer::Listings.new(@rentjuicer)
55
+ mock_get('/listings.json', 'listings.json', {
56
+ :neighborhoods => "South Boston",
57
+ :order_by => "rent",
58
+ :order_direction => "asc"
59
+ })
60
+ @results = @listings.search(:neighborhoods => "South Boston")
61
+ end
62
+
63
+ it "should allow response.body methods to be called on response" do
64
+ body = stub(:total_count => 25)
65
+ @results.body = body
66
+ @results.total_count.should == 25
67
+ end
68
+
69
+ it "should call super if body does not response to the method" do
70
+ lambda { @results.bad_method }.should raise_error(NoMethodError, /undefined method `bad_method'/)
71
+ end
72
+ end
73
+
51
74
  end
@@ -0,0 +1,8 @@
1
+ {
2
+ "status": "ok",
3
+ "page": 1,
4
+ "count": 0,
5
+ "total_count": 0,
6
+ "listings": null,
7
+ "runtime": 0.056
8
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rentjuicer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tcocca
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.3.1
33
+ version: 0.4.0
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rash
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.1.1
43
+ version: 0.2.0
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: will_paginate
@@ -117,6 +117,7 @@ files:
117
117
  - spec/responses/lead_error.json
118
118
  - spec/responses/listings.json
119
119
  - spec/responses/neighborhoods.json
120
+ - spec/responses/no_listings.json
120
121
  - spec/spec.opts
121
122
  - spec/spec_helper.rb
122
123
  - spec/support/listing_helper.rb