simplificator-ruby-kiva 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +59 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/ruby-kiva/api.rb +55 -0
- data/lib/ruby-kiva/borrower.rb +21 -0
- data/lib/ruby-kiva/comment.rb +14 -0
- data/lib/ruby-kiva/country.rb +8 -0
- data/lib/ruby-kiva/dynamic_initializer.rb +30 -0
- data/lib/ruby-kiva/image.rb +20 -0
- data/lib/ruby-kiva/journal_entry.rb +32 -0
- data/lib/ruby-kiva/lender.rb +66 -0
- data/lib/ruby-kiva/lending_action.rb +25 -0
- data/lib/ruby-kiva/loan.rb +109 -0
- data/lib/ruby-kiva/location.rb +67 -0
- data/lib/ruby-kiva/paged_array.rb +66 -0
- data/lib/ruby-kiva/partner.rb +45 -0
- data/lib/ruby-kiva/payment.rb +11 -0
- data/lib/ruby-kiva/team.rb +28 -0
- data/lib/ruby-kiva/terms.rb +20 -0
- data/lib/ruby-kiva/video.rb +7 -0
- data/lib/simplificator-ruby-kiva.rb +7 -0
- data/simplificator-ruby-kiva.gemspec +85 -0
- data/test/helper.rb +11 -0
- data/test/test_simplificator-ruby-kiva.rb +7 -0
- data/test/unit/borrower_test.rb +50 -0
- data/test/unit/comment_test.rb +43 -0
- data/test/unit/country_test.rb +39 -0
- data/test/unit/image_test.rb +48 -0
- data/test/unit/journal_entry_test.rb +60 -0
- data/test/unit/lender_test.rb +82 -0
- data/test/unit/payment_test.rb +28 -0
- metadata +115 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 pascalbetz
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= simplificator-ruby-kiva
|
2
|
+
|
3
|
+
== What
|
4
|
+
This is a ruby wrapper for the kiva.org api.
|
5
|
+
See build.kiva.org for details.
|
6
|
+
|
7
|
+
== Howtow
|
8
|
+
|
9
|
+
include Kiva
|
10
|
+
|
11
|
+
Api.app_id = 'your api id here, not required but recommended, see build.kiva.org'
|
12
|
+
### Loans
|
13
|
+
## finding Loans by ID
|
14
|
+
|
15
|
+
#puts Loan.find(:id => 180009).terms
|
16
|
+
#puts Loan.find(:id => '180009, 180008').size
|
17
|
+
#puts Loan.find(:id => [180009, '180008']).size
|
18
|
+
|
19
|
+
## finding Loans by lender_id
|
20
|
+
#puts Loan.find(:lender_id => 'matt', :page => 1).inspect
|
21
|
+
|
22
|
+
## finding Loans
|
23
|
+
#puts Loan.find(:query => 'Chinchilla', :page => 1).inspect
|
24
|
+
#puts Loan.find(:partner_id => [150, 156, 188, 190, 120], :query => 'Vegetable', :status => :in_repayment, :page => 2).inspect
|
25
|
+
|
26
|
+
### Partners
|
27
|
+
|
28
|
+
#puts Partner.find().first.inspect
|
29
|
+
#puts Partner.find(:id => 1).inspect
|
30
|
+
|
31
|
+
|
32
|
+
### Lending Actions
|
33
|
+
#LendingAction.recent.first
|
34
|
+
|
35
|
+
|
36
|
+
### Journal Entries
|
37
|
+
#puts JournalEntry.find(:loan_id => 180009, :include_bulk => true, :page => 10).inspect
|
38
|
+
#puts Loan.find(:id => 180009).journal_entries(:include_bulk => true).first.comments
|
39
|
+
#puts Comment.find(:journal_entry_id => 28342).inspect
|
40
|
+
|
41
|
+
|
42
|
+
### Team
|
43
|
+
#puts Team.find(:id => 2).team_since
|
44
|
+
#puts Team.find(:shortname => 'buildkiva')
|
45
|
+
#puts Team.find(:id => 6341).lenders(:page => 1).inspect
|
46
|
+
|
47
|
+
== Note on Patches/Pull Requests
|
48
|
+
|
49
|
+
* Fork the project.
|
50
|
+
* Make your feature addition or bug fix.
|
51
|
+
* Add tests for it. This is important so I don't break it in a
|
52
|
+
future version unintentionally.
|
53
|
+
* Commit, do not mess with rakefile, version, or history.
|
54
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
55
|
+
* Send me a pull request. Bonus points for topic branches.
|
56
|
+
|
57
|
+
== Copyright
|
58
|
+
|
59
|
+
Copyright (c) 2010 pascalbetz. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "simplificator-ruby-kiva"
|
8
|
+
gem.summary = %Q{a ruby wrapper for the kiva.org api}
|
9
|
+
gem.description = %Q{a ruby wrapper for the kiva.org api}
|
10
|
+
gem.email = "info@simplificator.com"
|
11
|
+
gem.homepage = "http://github.com/simplificator/simplificator-ruby-kiva"
|
12
|
+
gem.authors = ["simplificator"]
|
13
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "simplificator-ruby-kiva #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Kiva
|
2
|
+
module Api
|
3
|
+
def self.app_id=(value)
|
4
|
+
@@app_id = value
|
5
|
+
end
|
6
|
+
def self.app_id
|
7
|
+
@@app_id
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
private
|
13
|
+
def json_to_paged_array(data, data_key, many)
|
14
|
+
if many
|
15
|
+
if data[data_key]
|
16
|
+
PagedArray.new(data[data_key].map { |item| self.new(item)}, data['paging'] || {})
|
17
|
+
else
|
18
|
+
PagedArray.new([], {})
|
19
|
+
end
|
20
|
+
else
|
21
|
+
if data[data_key]
|
22
|
+
self.new(data[data_key].first)
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_options(options = {})
|
30
|
+
if Api.app_id
|
31
|
+
{:app_id => Api.app_id}.merge(pagination_options(options))
|
32
|
+
else
|
33
|
+
pagination_options(options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def pagination_options(options = {})
|
38
|
+
{ :page => options[:page] || 1}
|
39
|
+
end
|
40
|
+
|
41
|
+
def sanitize_id_parameter(id)
|
42
|
+
Array(id).join(',').gsub(/\s/, '')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.included(receiver)
|
48
|
+
receiver.instance_eval do
|
49
|
+
extend ClassMethods
|
50
|
+
include HTTParty
|
51
|
+
base_uri 'http://api.kivaws.org/v1'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Borrower
|
3
|
+
include DynamicInitializer
|
4
|
+
attr_accessor :gender, :pictured, :first_name, :last_name
|
5
|
+
|
6
|
+
def male?
|
7
|
+
self.gender == 'M'
|
8
|
+
end
|
9
|
+
def female?
|
10
|
+
self.gender == 'F'
|
11
|
+
end
|
12
|
+
|
13
|
+
def pictured?
|
14
|
+
self.pictured
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"<#{self.first_name} #{self.last_name} #{self.gender} #{self.pictured?}>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Comment
|
3
|
+
include DynamicInitializer
|
4
|
+
include Api
|
5
|
+
attr_accessor :id, :author, :whereabouts, :body, :date
|
6
|
+
typed_attr_accessor :date, Time, :parse
|
7
|
+
|
8
|
+
def self.find(params)
|
9
|
+
if params[:journal_entry_id]
|
10
|
+
json_to_paged_array(get("/journal_entries/#{params[:journal_entry_id]}/comments.json", :query => base_options(params)), 'comments', true)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Kiva
|
2
|
+
module DynamicInitializer
|
3
|
+
module ClassMethods
|
4
|
+
def typed_attr_accessor(name, klass, factory_method = :new, array = false)
|
5
|
+
define_method("#{name}=") do |value|
|
6
|
+
if array
|
7
|
+
typed = value.map() {|item| klass.send(factory_method, item)}
|
8
|
+
else
|
9
|
+
typed = klass.send(factory_method, value)
|
10
|
+
end
|
11
|
+
instance_variable_set("@#{name}", typed)
|
12
|
+
end
|
13
|
+
attr_reader name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def initialize(options = {})
|
19
|
+
options.each do |key, value|
|
20
|
+
self.send("#{key}=", value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(receiver)
|
26
|
+
receiver.extend ClassMethods
|
27
|
+
receiver.send :include, InstanceMethods
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Image
|
3
|
+
include DynamicInitializer
|
4
|
+
attr_accessor :template_id, :id
|
5
|
+
|
6
|
+
SIZES = %w(w80h80 w200h200 w325h250 w450h360 fullsize)
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
"<Image #{self.template_id} / #{self.id}>"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Build the URL for this Image.
|
13
|
+
# See SIZES for valid sizes, defaults to w80h80
|
14
|
+
def url(size = 'w80h80')
|
15
|
+
raise 'Must have a template id and an id' unless self.template_id && self.id
|
16
|
+
raise "Unknown size #{size}" unless SIZES.include?(size.to_s)
|
17
|
+
"http://www.kiva.org/img/#{size}/#{self.id}.jpg"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Kiva
|
2
|
+
class JournalEntry
|
3
|
+
include DynamicInitializer
|
4
|
+
include Api
|
5
|
+
attr_accessor :id, :body, :subject, :author, :bulk, :comment_count, :recommendation_count
|
6
|
+
|
7
|
+
typed_attr_accessor :date, Time, :parse
|
8
|
+
|
9
|
+
def bulk?
|
10
|
+
self.bulk
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find(params)
|
14
|
+
if params[:loan_id]
|
15
|
+
json_to_paged_array(get("/loans/#{params[:loan_id]}/journal_entries.json",
|
16
|
+
:query => base_options.merge(find_options(params))), 'journal_entries', true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def comments(params = {})
|
21
|
+
@comments ||= Comment.find(params.merge({:journal_entry_id => self.id}))
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def self.find_options(options)
|
27
|
+
result = {}
|
28
|
+
result['include_bulk'] = options[:include_bulk] ? 1 : 0
|
29
|
+
result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Lender
|
3
|
+
include Api
|
4
|
+
include DynamicInitializer
|
5
|
+
attr_accessor :loan_count, :occupation, :country_code, :name, :loan_because,
|
6
|
+
:lender_id, :uid, :whereabouts, :invitee_count,
|
7
|
+
:occupational_info, :personal_url
|
8
|
+
|
9
|
+
typed_attr_accessor :member_since, Time, :parse
|
10
|
+
typed_attr_accessor :team_join_date, Time, :parse
|
11
|
+
typed_attr_accessor :image, Kiva::Image
|
12
|
+
|
13
|
+
def lender_page_url
|
14
|
+
"http://www.kiva.org/lender/#{self.lender_id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
# find the loans for this lender
|
18
|
+
# loans are cached to avoid roundtrips, refetch the lender if you need to refresh loans
|
19
|
+
def loans(params = {})
|
20
|
+
@loans ||= Loan.find(params.merge({:lender_id => self.lender_id}))
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s()
|
24
|
+
"<Lender #{self.lender_id}>"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Find Lenders
|
28
|
+
# __either__
|
29
|
+
# :id : A single ID or a comma Separated String of IDs or an Array of IDs
|
30
|
+
# __or__
|
31
|
+
# :loan_id : A single loan ID
|
32
|
+
# __or__
|
33
|
+
# :team_id : a single team ID
|
34
|
+
#
|
35
|
+
# If searching for a single ID, then this method can return nil (no item with this ID found).
|
36
|
+
# Otherwise this method will always return a PagedArray instance (which might be empty though)
|
37
|
+
# If querying for multiple items, then :page is supported
|
38
|
+
def self.find(params)
|
39
|
+
if params[:id] # find one or many by lender ID
|
40
|
+
data = get("/lenders/#{sanitize_id_parameter(params[:id])}.json", :query => base_options(params))
|
41
|
+
many = sanitize_id_parameter(params[:id]).include?(',')
|
42
|
+
elsif params[:loan_id] # find lenders for a loan
|
43
|
+
data = get("/loans/#{params[:loan_id]}/lenders.json", :query => base_options(params))
|
44
|
+
many = true
|
45
|
+
elsif params[:team_id]
|
46
|
+
data = get("/teams/#{params[:team_id]}/lenders.json", :query => base_options(params))
|
47
|
+
many = true
|
48
|
+
end
|
49
|
+
json_to_paged_array(data, 'lenders', many)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# {"loan_count"=>93,
|
55
|
+
# "occupation"=>"Entrepreneur",
|
56
|
+
# "country_code"=>"US",
|
57
|
+
# "name"=>"Matt",
|
58
|
+
# "loan_because"=>"I love the stories. ",
|
59
|
+
# "lender_id"=>"matt",
|
60
|
+
# "invitee_count"=>23,
|
61
|
+
# "occupational_info"=>"I co-founded a startup nonprofit (this one!) and I work with an amazing group of people dreaming up ways to alleviate poverty through personal lending. ",
|
62
|
+
# "personal_url"=>"www.socialedge.org/blogs/kiva-chronicles",
|
63
|
+
# "uid"=>"matt",
|
64
|
+
# "whereabouts"=>"San Francisco CA",
|
65
|
+
# "image"=>{"template_id"=>1, "id"=>12829},
|
66
|
+
# "member_since"=>"2006-01-01T09:01:01Z"}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kiva
|
2
|
+
class LendingAction
|
3
|
+
include Api
|
4
|
+
include DynamicInitializer
|
5
|
+
|
6
|
+
attr_accessor :id, :sector, :basket_amount
|
7
|
+
|
8
|
+
typed_attr_accessor :date, Time, :parse
|
9
|
+
typed_attr_accessor :lender, Kiva::Lender
|
10
|
+
typed_attr_accessor :loan, Kiva::Loan
|
11
|
+
|
12
|
+
|
13
|
+
def self.recent(options = {})
|
14
|
+
json_to_paged_array(get('/lending_actions/recent.json'), 'lending_actions', true)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#{"date"=>"2010-04-09T22:00:27Z",
|
21
|
+
#{}"id"=>33614166,
|
22
|
+
#{}"lender"=>{"country_code"=>"US", "name"=>"Eisakouo Partnership", "lender_id"=>"eisakouopartnership3932", "uid"=>"eisakouopartnership3932", "whereabouts"=>"Columbia PA", "image"=>{"template_id"=>1, "id"=>482823}},
|
23
|
+
#{}"loan"=>{"borrower_count"=>1, "status"=>"fundraising", "name"=>"Laoy Lok", "posted_date"=>"2010-04-07T06:40:02Z", "activity"=>"Cattle", "id"=>191433, "description"=>{"languages"=>["en"]}, "partner_id"=>109, "use"=>"To buy a cow for breeding", "loan_amount"=>300, "funded_amount"=>0, "image"=>{"template_id"=>1, "id"=>520519}, "location"=>{"country_code"=>"KH", "country"=>"Cambodia", "geo"=>{"type"=>"point", "level"=>"country", "pairs"=>"13 105"}, "town"=>"Rung Village"},
|
24
|
+
#{}"sector"=>"Agriculture",
|
25
|
+
#{}"basket_amount"=>0}}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Loan
|
3
|
+
include Api
|
4
|
+
include DynamicInitializer
|
5
|
+
|
6
|
+
attr_accessor :name, :activity, :use, :borrower_count,
|
7
|
+
:status, :id, :partner_id, :description,
|
8
|
+
:loan_amount, :funded_amount, :paid_amount, :basket_amount, :sector,
|
9
|
+
:delinquent, :journal_totals, :terms, :funded_date
|
10
|
+
|
11
|
+
typed_attr_accessor :location, Kiva::Location
|
12
|
+
typed_attr_accessor :image, Kiva::Image
|
13
|
+
typed_attr_accessor :video, Kiva::Video
|
14
|
+
typed_attr_accessor :terms, Kiva::Terms
|
15
|
+
typed_attr_accessor :posted_date, Date, :parse
|
16
|
+
typed_attr_accessor :borrowers, Kiva::Borrower, :new, true
|
17
|
+
|
18
|
+
# description consists of available languages and texts in different languages
|
19
|
+
# texts are only available when doing a find by id
|
20
|
+
def description=(value)
|
21
|
+
@description = value
|
22
|
+
@description_languages = value['languages']
|
23
|
+
@description_texts = value['texts']
|
24
|
+
end
|
25
|
+
|
26
|
+
def description_languages
|
27
|
+
@description_languages
|
28
|
+
end
|
29
|
+
|
30
|
+
def description_texts
|
31
|
+
@description_texts
|
32
|
+
end
|
33
|
+
|
34
|
+
def description_text(language)
|
35
|
+
description_texts[language]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get the lenders for this loan
|
39
|
+
# Caches the lenders, reload loan if you need to refresh the lenders
|
40
|
+
def lenders(params = {})
|
41
|
+
@lenders ||= Lender.find(params.merge({:loan_id => self.id}))
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def journal_entries(params = {})
|
46
|
+
@journal_entries ||= JournalEntry.find(params.merge({:loan_id => self.id}))
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Supported options:
|
51
|
+
# * :page: The requested page number
|
52
|
+
def self.recent(options = {})
|
53
|
+
data = get('/loans/newest.json', :query => base_options(options))
|
54
|
+
json_to_paged_array(data, 'loans', true)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Search for Loans.
|
58
|
+
# Different searches are possible
|
59
|
+
# __either:__
|
60
|
+
# :id: An ID, a comma delimited String of IDs or an Array of IDs
|
61
|
+
# __or__
|
62
|
+
# :lender_id: A single ID of a lender
|
63
|
+
# __or__
|
64
|
+
# :team_id : a single ID of a team
|
65
|
+
# __or a combination of__
|
66
|
+
# * :partner_id: A (comma delimited) String of Partner IDs or an Array of partner IDs
|
67
|
+
# * :status: A String or symbol with the Loan status
|
68
|
+
# * :query: A String
|
69
|
+
#
|
70
|
+
# If searching for a single ID, then this method can return nil (no item with this ID found).
|
71
|
+
# Otherwise this method will always return a PagedArray instance (which might be empty though)
|
72
|
+
#
|
73
|
+
# When searching for multiple Loans, then the :page parameter is supported to specify the desired page.
|
74
|
+
def self.find(params)
|
75
|
+
if params[:id] # find one or many by ID
|
76
|
+
data = get("/loans/#{sanitize_id_parameter(params[:id])}.json", :query => base_options(params))
|
77
|
+
many = sanitize_id_parameter(params[:id]).include?(',')
|
78
|
+
elsif params[:lender_id] # find all loans for a lender
|
79
|
+
data = get("/lenders/#{params[:lender_id]}/loans.json", :query => base_options(params))
|
80
|
+
many = true
|
81
|
+
elsif params[:team_id] # find all loans for a team
|
82
|
+
data = get("/teams/#{params[:team_id]}/loans.json", :query => base_options(params))
|
83
|
+
many = true
|
84
|
+
else # search
|
85
|
+
data = get('/loans/search.json', :query => base_options(params).merge(find_options(params)))
|
86
|
+
many = true
|
87
|
+
end
|
88
|
+
json_to_paged_array(data, 'loans', many)
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s()
|
92
|
+
"<Loan '%s' (%s) in %s with status %s, from %s>" % [self.name, self.id, self.location, self.status, self.borrowers]
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def self.find_options(options = {})
|
98
|
+
result = {}
|
99
|
+
if options[:partner_id]
|
100
|
+
result[:partner] = sanitize_id_parameter(options[:partner_id])
|
101
|
+
end
|
102
|
+
result[:status] = options[:status] if options[:status]
|
103
|
+
result[:q] = options[:query] if options[:query]
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Kiva
|
2
|
+
class Location
|
3
|
+
include DynamicInitializer
|
4
|
+
attr_accessor :country, :geo, :town, :type, :level
|
5
|
+
attr_accessor :country_code
|
6
|
+
|
7
|
+
def geo=(value)
|
8
|
+
self.type = value['type']
|
9
|
+
self.level = value['level']
|
10
|
+
self.pairs = value['pairs']
|
11
|
+
end
|
12
|
+
|
13
|
+
def pairs=(value)
|
14
|
+
@pairs = value.split(' ').map() {|item| item.to_f}
|
15
|
+
end
|
16
|
+
|
17
|
+
def pairs
|
18
|
+
@pairs.join(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# if this is a point?, then returns lat else nil
|
23
|
+
def lat
|
24
|
+
@pairs[0] if self.point?
|
25
|
+
end
|
26
|
+
|
27
|
+
# if this is a point?, then returns lat else nil
|
28
|
+
def lng
|
29
|
+
@pairs[1] if self.point?
|
30
|
+
end
|
31
|
+
|
32
|
+
# true if level is 'town'
|
33
|
+
def town?
|
34
|
+
'town' == self.level
|
35
|
+
end
|
36
|
+
# true if level is 'country'
|
37
|
+
def country?
|
38
|
+
'country' == self.level
|
39
|
+
end
|
40
|
+
# true if level 'exact'
|
41
|
+
def exact?
|
42
|
+
'exact' == self.level
|
43
|
+
end
|
44
|
+
|
45
|
+
# true if type 'point'
|
46
|
+
def point?
|
47
|
+
'point' == self.type
|
48
|
+
end
|
49
|
+
# true if type 'line'
|
50
|
+
def line?
|
51
|
+
'line' == self.type
|
52
|
+
end
|
53
|
+
# true if type 'box'
|
54
|
+
def box?
|
55
|
+
'box' == self.type
|
56
|
+
end
|
57
|
+
# true if type 'polygon'
|
58
|
+
def polygon?
|
59
|
+
'polygon' == self.type
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
"<Location '%s' '%s' %f/%f>" % [self.country, self.town, self.lat || 0, self.lng || 0]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Kiva
|
2
|
+
# Adds pagination information to array
|
3
|
+
# Pagination attributes/methods have the same names as the wonderful will_paginate
|
4
|
+
class PagedArray < Array
|
5
|
+
attr_reader :current_page, :per_page, :total_entries, :total_pages
|
6
|
+
|
7
|
+
def initialize(data, options = {})
|
8
|
+
super data
|
9
|
+
@current_page = options['page'] || 1
|
10
|
+
@per_page = options['page_size'] || data.size
|
11
|
+
@total_pages = options['pages'] || 1
|
12
|
+
@total_entries = options['total'] || data.size
|
13
|
+
end
|
14
|
+
|
15
|
+
def offset
|
16
|
+
(self.current_page - 1) * self.per_page
|
17
|
+
end
|
18
|
+
|
19
|
+
def next_page?()
|
20
|
+
self.current_page < self.total_pages
|
21
|
+
end
|
22
|
+
|
23
|
+
def next_page
|
24
|
+
self.current_page + 1 if next_page?
|
25
|
+
end
|
26
|
+
|
27
|
+
def previous_page
|
28
|
+
self.current_page - 1 if previous_page?
|
29
|
+
end
|
30
|
+
|
31
|
+
def previous_page?()
|
32
|
+
self.current_page > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def from_entry
|
36
|
+
self.offset + 1 unless self.out_of_bounds?
|
37
|
+
end
|
38
|
+
|
39
|
+
def out_of_bounds?
|
40
|
+
self.current_page < 1 || self.current_page > self.total_pages
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_entry
|
44
|
+
[self.offset + self.per_page, self.total_entries].min unless self.out_of_bounds?
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
"#{pagination_info}\n#{super}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
self.inspect
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
|
58
|
+
def pagination_info
|
59
|
+
if out_of_bounds?
|
60
|
+
"<Page is out of bounds>"
|
61
|
+
else
|
62
|
+
"<Page #{self.current_page} of #{self.total_pages} (entries #{self.from_entry} - #{self.to_entry} of #{self.total_entries}). Previous? #{self.previous_page?}, Next? #{self.next_page?}>"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|