simplificator-ruby-kiva 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,7 +4,23 @@
4
4
  This is a ruby wrapper for the kiva.org api.
5
5
  See build.kiva.org for details.
6
6
 
7
- == Howtow
7
+ == Status
8
+
9
+ Still work in progress, some tests are missing, documentation is quite weak.
10
+ Most API calls from Kiva are reflected.
11
+ http://build.kiva.org/api offers a list of API methods, not implemented: Methods, Release, Templates
12
+
13
+ == Attention
14
+
15
+ Whenever the unknown elements are encountered in the JSON documents, then an exception is raised.
16
+ Let me know if this happens and i will add the missing attributes. Or set Kiva::Api.friendly = true AND let me know.
17
+
18
+
19
+ == History
20
+ 0.2.0 Updated API to include more functionality, added some tests
21
+ 0.1.0 Initial Release
22
+
23
+ == Howto
8
24
 
9
25
  include Kiva
10
26
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/lib/ruby-kiva/api.rb CHANGED
@@ -1,15 +1,49 @@
1
1
  module Kiva
2
2
  module Api
3
+ # set the API id
3
4
  def self.app_id=(value)
4
5
  @@app_id = value
5
6
  end
7
+ # retrieve the API id
6
8
  def self.app_id
7
- @@app_id
9
+ @@app_id if defined? @@app_id
10
+ end
11
+
12
+ def self.friendly=(value)
13
+ @@friendly = value
14
+ end
15
+ def self.friendly
16
+ @@friendly if defined? @@friendly
8
17
  end
9
18
 
10
19
 
11
20
  module ClassMethods
12
21
  private
22
+ # map options to a new hash
23
+ # options
24
+ # mappings, an Array with up to 4 elements: [:source_key, :destination_key, sanitize (true, false), valid items]
25
+ # if mapping size is 1, then items are just copied over to new hash using same key
26
+ # if mapping size is 2, then items are copied over using :destination_key as the new key
27
+ # if mapping size is 3, then value is sanitized if mappind[2]
28
+ # if mapping size is 4, then value is verified to be included in mapping[3]
29
+ #
30
+ # if the value is nil in the options hash, then it is not copied
31
+ def map_options(options, mappings)
32
+ result = {}
33
+ mappings.each do |mapping|
34
+ if options.has_key?(mapping[0])
35
+ value = options[mapping[0]]
36
+ raise "Invalid value for #{mapping[0]}: #{value}" if mapping[3] && !mapping[3].include?(value)
37
+ result[mapping[1] || mapping[0]] = mapping[2] ? sanitize_id_parameter(value) : value
38
+ end
39
+ end
40
+ result
41
+ end
42
+
43
+ # converts JSON to a PagedArray or a single Instance of a ruby-kiva Api class
44
+ # data: the JSON Date
45
+ # data_key, the key under which the date for a item is stored
46
+ # many if true: create an array / if false: create a single instance
13
47
  def json_to_paged_array(data, data_key, many)
14
48
  if many
15
49
  if data[data_key]
@@ -26,20 +60,23 @@ module Kiva
26
60
  end
27
61
  end
28
62
 
63
+ # basic options
64
+ # includes App ID if set and adds pagination options if required
29
65
  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
66
+ result = pagination_options(options)
67
+ result[:app_id] = Api.app_id if Api.app_id
68
+ result
35
69
  end
36
70
 
71
+ # builds a new hash with pagination options
37
72
  def pagination_options(options = {})
38
- { :page => options[:page] || 1}
73
+ options[:page] ? {:page => options[:page]} : {}
39
74
  end
40
75
 
76
+ # sanitizes ID parameters for use in path of service
77
+ # pass a String or an Array with IDs, returns a comman separated String of IDs, whitespaces removed
41
78
  def sanitize_id_parameter(id)
42
- Array(id).join(',').gsub(/\s/, '')
79
+ Array(id).flatten.join(',').gsub(/\s/, '')
43
80
  end
44
81
  end
45
82
 
@@ -2,22 +2,26 @@ module Kiva
2
2
  module DynamicInitializer
3
3
  module ClassMethods
4
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)
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)
12
10
  end
13
- attr_reader name
11
+ instance_variable_set("@#{name}", typed)
12
+ end
13
+ attr_reader name
14
14
  end
15
15
  end
16
16
 
17
17
  module InstanceMethods
18
18
  def initialize(options = {})
19
19
  options.each do |key, value|
20
- self.send("#{key}=", value)
20
+ if respond_to?("#{key}=")
21
+ self.send("#{key}=", value)
22
+ elsif !Api.friendly
23
+ raise "Attribute #{key} is not yet supported. Set Api.friendly = true"
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -5,6 +5,8 @@ module Kiva
5
5
  attr_accessor :id, :body, :subject, :author, :bulk, :comment_count, :recommendation_count
6
6
 
7
7
  typed_attr_accessor :date, Time, :parse
8
+ typed_attr_accessor :image, Kiva::Image
9
+ typed_attr_accessor :video, Kiva::Video
8
10
 
9
11
  def bulk?
10
12
  self.bulk
@@ -13,7 +15,10 @@ module Kiva
13
15
  def self.find(params)
14
16
  if params[:loan_id]
15
17
  json_to_paged_array(get("/loans/#{params[:loan_id]}/journal_entries.json",
16
- :query => base_options.merge(find_options(params))), 'journal_entries', true)
18
+ :query => sanitize_options(params)), 'journal_entries', true)
19
+ else
20
+ json_to_paged_array(get("/journal_entries/search.json",
21
+ :query => sanitize_options(params)), 'journal_entries', true)
17
22
  end
18
23
  end
19
24
 
@@ -23,10 +28,17 @@ module Kiva
23
28
 
24
29
  private
25
30
 
26
- def self.find_options(options)
27
- result = {}
31
+ OPTION_MAPPINGS = [
32
+ [:media, :media, false, ['any', 'video', 'image']],
33
+ [:sort_by, :sort_by, false, ['newest', 'oldest', 'recommendation_count', 'comment_count']],
34
+ [:partner_id, :partner, true],
35
+ [:query, :q]
36
+ ]
37
+ def self.sanitize_options(options = {})
38
+ result = base_options(options).merge(map_options(options, OPTION_MAPPINGS))
28
39
  result['include_bulk'] = options[:include_bulk] ? 1 : 0
29
40
  result
30
41
  end
42
+
31
43
  end
32
44
  end
@@ -24,30 +24,48 @@ module Kiva
24
24
  "<Lender #{self.lender_id}>"
25
25
  end
26
26
 
27
+ def self.newest(params = {})
28
+ json_to_paged_array(get('/lenders/newest.json', :query => sanitize_options(params)), 'lenders', true)
29
+ end
30
+
27
31
  # Find Lenders
28
32
  # __either__
29
33
  # :id : A single ID or a comma Separated String of IDs or an Array of IDs
30
34
  # __or__
31
35
  # :loan_id : A single loan ID
32
36
  # __or__
33
- # :team_id : a single team ID
37
+ # :team_id : a single team ID, supports :sort_by
34
38
  #
35
39
  # If searching for a single ID, then this method can return nil (no item with this ID found).
36
40
  # Otherwise this method will always return a PagedArray instance (which might be empty though)
37
41
  # If querying for multiple items, then :page is supported
38
- def self.find(params)
42
+ def self.find(params = {})
39
43
  if params[:id] # find one or many by lender ID
40
- data = get("/lenders/#{sanitize_id_parameter(params[:id])}.json", :query => base_options(params))
44
+ data = get("/lenders/#{sanitize_id_parameter(params[:id])}.json", :query => sanitize_options(params))
41
45
  many = sanitize_id_parameter(params[:id]).include?(',')
42
46
  elsif params[:loan_id] # find lenders for a loan
43
- data = get("/loans/#{params[:loan_id]}/lenders.json", :query => base_options(params))
47
+ data = get("/loans/#{params[:loan_id]}/lenders.json", :query => sanitize_options(params))
44
48
  many = true
45
49
  elsif params[:team_id]
46
- data = get("/teams/#{params[:team_id]}/lenders.json", :query => base_options(params))
50
+ data = get("/teams/#{params[:team_id]}/lenders.json", :query => sanitize_options(params))
51
+ many = true
52
+ else
53
+ data = get("/lenders/search.json", :query => sanitize_options(params))
47
54
  many = true
48
55
  end
49
56
  json_to_paged_array(data, 'lenders', many)
50
57
  end
58
+
59
+ private
60
+ OPTION_MAPPINGS = [
61
+ [:sort_by, :sort_by, false, ['oldest', 'newest']],
62
+ [:occupation],
63
+ [:query, :q]
64
+ ]
65
+ def self.sanitize_options(options = {})
66
+ base_options(options).merge(map_options(options, OPTION_MAPPINGS))
67
+ end
68
+
51
69
  end
52
70
  end
53
71
 
@@ -10,9 +10,13 @@ module Kiva
10
10
  typed_attr_accessor :loan, Kiva::Loan
11
11
 
12
12
 
13
- def self.recent(options = {})
13
+ def self.newest(options = {})
14
14
  json_to_paged_array(get('/lending_actions/recent.json'), 'lending_actions', true)
15
15
  end
16
+ # renamed from recent to 'newest' to make it consistent with LendingAction and Lender
17
+ class <<self
18
+ alias_method :recent, :newest
19
+ end
16
20
 
17
21
  end
18
22
  end
@@ -13,7 +13,9 @@ module Kiva
13
13
  typed_attr_accessor :video, Kiva::Video
14
14
  typed_attr_accessor :terms, Kiva::Terms
15
15
  typed_attr_accessor :posted_date, Date, :parse
16
+ typed_attr_accessor :paid_date, Date, :parse
16
17
  typed_attr_accessor :borrowers, Kiva::Borrower, :new, true
18
+ typed_attr_accessor :payments, Kiva::Payment, :new, true
17
19
 
18
20
  # description consists of available languages and texts in different languages
19
21
  # texts are only available when doing a find by id
@@ -46,10 +48,14 @@ module Kiva
46
48
  @journal_entries ||= JournalEntry.find(params.merge({:loan_id => self.id}))
47
49
  end
48
50
 
51
+ def loan_updates
52
+ @loan_updates ||= find_loan_updates()
53
+ end
54
+
49
55
 
50
56
  # Supported options:
51
57
  # * :page: The requested page number
52
- def self.recent(options = {})
58
+ def self.newest(options = {})
53
59
  data = get('/loans/newest.json', :query => base_options(options))
54
60
  json_to_paged_array(data, 'loans', true)
55
61
  end
@@ -73,35 +79,52 @@ module Kiva
73
79
  # When searching for multiple Loans, then the :page parameter is supported to specify the desired page.
74
80
  def self.find(params)
75
81
  if params[:id] # find one or many by ID
76
- data = get("/loans/#{sanitize_id_parameter(params[:id])}.json", :query => base_options(params))
82
+ data = get("/loans/#{sanitize_id_parameter(params[:id])}.json", :query => sanitize_options(params))
77
83
  many = sanitize_id_parameter(params[:id]).include?(',')
78
84
  elsif params[:lender_id] # find all loans for a lender
79
- data = get("/lenders/#{params[:lender_id]}/loans.json", :query => base_options(params))
85
+ data = get("/lenders/#{params[:lender_id]}/loans.json", :query => sanitize_options(params))
80
86
  many = true
81
87
  elsif params[:team_id] # find all loans for a team
82
- data = get("/teams/#{params[:team_id]}/loans.json", :query => base_options(params))
88
+ data = get("/teams/#{params[:team_id]}/loans.json", :query => sanitize_options(params))
83
89
  many = true
84
90
  else # search
85
- data = get('/loans/search.json', :query => base_options(params).merge(find_options(params)))
91
+ puts "Searching with #{base_options(params).merge(find_options(params)).inspect}"
92
+ data = get('/loans/search.json', :query => sanitize_options(params))
86
93
  many = true
87
94
  end
88
95
  json_to_paged_array(data, 'loans', many)
89
96
  end
90
97
 
91
98
  def to_s()
92
- "<Loan '%s' (%s) in %s with status %s, from %s>" % [self.name, self.id, self.location, self.status, self.borrowers]
99
+ "<Loan '%s' (%s) in %s with status %s, from %s>" % [self.name, self.id, self.location, self.id, self.borrowers]
93
100
  end
94
101
 
95
102
  private
96
103
 
97
- def self.find_options(options = {})
98
- result = {}
99
- if options[:partner_id]
100
- result[:partner] = sanitize_id_parameter(options[:partner_id])
104
+ def find_loan_updates
105
+ data = Loan.get("/loans/#{self.id}/updates.json")
106
+ data['loan_updates'].map do |entry|
107
+ type = entry.delete('update_type')
108
+ case type
109
+ when 'journal_entry' then JournalEntry.new(entry['journal_entry'])
110
+ when 'payment' then Payment.new(entry['payment'])
111
+ else raise "unknown type #{type}"
112
+ end
101
113
  end
102
- result[:status] = options[:status] if options[:status]
103
- result[:q] = options[:query] if options[:query]
104
- result
114
+ end
115
+
116
+ OPTION_MAPPINGS = [
117
+ [:partner_id, :partner, true],
118
+ [:sort_by, :sort_by, false, ['oldest', 'newest']],
119
+ [:status, :status, false, ['fundraising', 'funded', 'in_repayment', 'paid', 'defaulted']],
120
+ [:query, :q],
121
+ [:gender, :gender, false, ['male', 'female']],
122
+ [:region, :region, false, ['na', 'ca', 'sa', 'af', 'as', 'me', 'ee']],
123
+ [:sector],
124
+ [:country_code],
125
+ ]
126
+ def self.sanitize_options(options = {})
127
+ base_options(options).merge(map_options(options, OPTION_MAPPINGS))
105
128
  end
106
129
 
107
130
 
@@ -9,8 +9,9 @@ module Kiva
9
9
 
10
10
  # Find a partner
11
11
  # either by :id or all of them
12
- # Since kiva does not offer pagination or search,
12
+ # Since kiva does not offer search,
13
13
  # finding by id is implemented in memory/ruby.
14
+ # Pagination is not supported, page size is 200 and currently there are 143 partners
14
15
  # Items are cached but can be reloaded by passing :reload => true (caching is suggested by kiva...)
15
16
  def self.find(params = {})
16
17
  if params[:id]
@@ -1,8 +1,10 @@
1
1
  module Kiva
2
2
  class Payment
3
3
  include DynamicInitializer
4
- attr_accessor :amount
4
+ attr_accessor :amount, :local_amount, :rounded_local_amount, :comment, :payment_id
5
5
  typed_attr_accessor :due_date, Time, :parse
6
+ typed_attr_accessor :settlement_date, Time, :parse
7
+ typed_attr_accessor :processed_date, Time, :parse
6
8
 
7
9
  def to_s
8
10
  "<Payment due at #{self.due_date} : #{self.amount}>"
@@ -1,5 +1,6 @@
1
1
  module Kiva
2
2
  class Team
3
+
3
4
  include DynamicInitializer
4
5
  include Api
5
6
 
@@ -19,10 +20,31 @@ module Kiva
19
20
  # find a team by :id or :shortname
20
21
  def self.find(params)
21
22
  if params[:id]
22
- json_to_paged_array(get("/teams/#{params[:id]}.json", :query => base_options(params)), 'teams', false)
23
+ data = get("/teams/#{sanitize_id_parameter(params[:id])}.json", :query => sanitize_options(params))
24
+ many = sanitize_id_parameter(params[:id]).include?(',')
23
25
  elsif params[:shortname]
24
- json_to_paged_array(get("/teams/using_shortname/#{params[:shortname]}.json", :query => base_options(params)), 'teams', false)
26
+ data = get("/teams/using_shortname/#{sanitize_id_parameter(params[:shortname])}.json", :query => sanitize_options(params))
27
+ many = sanitize_id_parameter(params[:shortnames]).include?(',')
28
+ else
29
+ data = get("/teams/search.json", :query => sanitize_options(params))
30
+ many = true
25
31
  end
32
+ json_to_paged_array(data, 'teams', many)
26
33
  end
34
+
35
+ private
36
+
37
+ OPTION_MAPPINGS = [
38
+ [:sort_by, :sort_by, false, ['oldest', 'newest']],
39
+ [:occupation],
40
+ [:query, :q],
41
+ [:country_code],
42
+ [:membership_type, :membership_type, false, ['open', 'closed']],
43
+ [:category, :category, false, ['Alumni Groups', 'Businesses', 'Businesses - Internal Groups', 'Clubs', 'Colleges/Universities', 'Common Interest', 'Events', 'Families', 'Field Partner Fans', 'Friends', 'Local Area', 'Memorials', 'Religious Congregations', 'Schools', 'Sports Groups', 'Youth Groups', 'Other']],
44
+ ]
45
+ def self.sanitize_options(options = {})
46
+ base_options(options).merge(map_options(options, OPTION_MAPPINGS))
47
+ end
48
+
27
49
  end
28
50
  end
@@ -4,4 +4,4 @@ require 'httparty'
4
4
  %w( dynamic_initializer api payment borrower location country image paged_array video terms loan
5
5
  lender partner lending_action journal_entry comment team).each do |name|
6
6
  require File.join(File.dirname(__FILE__), 'ruby-kiva', name)
7
- end
7
+ end
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{simplificator-ruby-kiva}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["simplificator"]
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 0.1.0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - simplificator