flickr_fu 0.1.6 → 0.3.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.
Files changed (58) hide show
  1. data/.gitignore +13 -0
  2. data/README +38 -1
  3. data/Rakefile +64 -13
  4. data/VERSION.yml +4 -0
  5. data/flickr_fu.gemspec +114 -32
  6. data/lib/flickr/auth.rb +8 -1
  7. data/lib/flickr/base.rb +75 -26
  8. data/lib/flickr/contact.rb +16 -0
  9. data/lib/flickr/contacts.rb +55 -0
  10. data/lib/flickr/errors.rb +20 -0
  11. data/lib/flickr/geo.rb +42 -0
  12. data/lib/flickr/license.rb +10 -0
  13. data/lib/flickr/location.rb +15 -0
  14. data/lib/flickr/photo.rb +130 -107
  15. data/lib/flickr/photos.rb +29 -11
  16. data/lib/flickr/photoset.rb +37 -0
  17. data/lib/flickr/photosets.rb +39 -0
  18. data/lib/flickr/token.rb +1 -1
  19. data/lib/flickr/urls.rb +44 -0
  20. data/lib/flickr_fu.rb +25 -2
  21. data/spec/fixtures/flickr/contacts/get_list-fail-99.xml +4 -0
  22. data/spec/fixtures/flickr/contacts/get_public_list-0.xml +7 -0
  23. data/spec/fixtures/flickr/photos/geo/get_location-0.xml +11 -0
  24. data/spec/fixtures/flickr/photos/geo/get_location-fail-2.xml +4 -0
  25. data/spec/fixtures/flickr/photos/get_info-0.xml +41 -0
  26. data/spec/fixtures/flickr/photos/get_info-1.xml +19 -0
  27. data/spec/fixtures/flickr/photos/get_sizes-0.xml +10 -0
  28. data/spec/fixtures/flickr/photos/get_sizes-1.xml +8 -0
  29. data/spec/fixtures/flickr/photos/licenses/get_info.xml +12 -0
  30. data/spec/fixtures/flickr/photosets/get_list-0.xml +13 -0
  31. data/spec/fixtures/flickr/photosets/get_photos-0.xml +7 -0
  32. data/spec/fixtures/flickr/test/echo-0.xml +5 -0
  33. data/spec/fixtures/flickr/test/null-fail-99.xml +4 -0
  34. data/spec/fixtures/flickr/urls/get_group-0.xml +4 -0
  35. data/spec/fixtures/flickr/urls/get_group-fail-1.xml +4 -0
  36. data/spec/fixtures/flickr/urls/get_user_photos-0.xml +4 -0
  37. data/spec/fixtures/flickr/urls/get_user_photos-fail-1.xml +4 -0
  38. data/spec/fixtures/flickr/urls/get_user_photos-fail-2.xml +4 -0
  39. data/spec/fixtures/flickr/urls/get_user_profile-0.xml +4 -0
  40. data/spec/fixtures/flickr/urls/get_user_profile-fail-1.xml +4 -0
  41. data/spec/fixtures/flickr/urls/get_user_profile-fail-2.xml +4 -0
  42. data/spec/fixtures/flickr/urls/lookup_group-0.xml +6 -0
  43. data/spec/fixtures/flickr/urls/lookup_group-fail-1.xml +4 -0
  44. data/spec/fixtures/flickr/urls/lookup_user-0.xml +6 -0
  45. data/spec/fixtures/flickr/videos/get_info-0.xml +31 -0
  46. data/spec/fixtures/flickr/videos/get_sizes-0.xml +13 -0
  47. data/spec/flickr/base_spec.rb +97 -0
  48. data/spec/flickr/contacts_spec.rb +47 -0
  49. data/spec/flickr/errors_spec.rb +21 -0
  50. data/spec/flickr/geo_spec.rb +20 -0
  51. data/spec/flickr/photo_spec.rb +140 -0
  52. data/spec/flickr/photos_spec.rb +50 -0
  53. data/spec/flickr/photosets_spec.rb +49 -0
  54. data/spec/flickr/test_spec.rb +34 -0
  55. data/spec/flickr/urls_spec.rb +99 -0
  56. data/spec/spec.opts +4 -0
  57. data/spec/spec_helper.rb +20 -0
  58. metadata +66 -7
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ rdoc
2
+ .DS_Store
3
+ *.gem
4
+ demo*
5
+ *~
6
+ *.sw*
7
+ .specification
8
+ nbproject/
9
+ doc/rspec_report.html
10
+ doc/rspec_profile.txt
11
+ spec/spec.local.opts
12
+ coverage/
13
+ pkg/
data/README CHANGED
@@ -23,6 +23,12 @@
23
23
 
24
24
  http://www.commonthread.com/projects/flickr_fu/rdoc/
25
25
 
26
+ == Example flickr.yml
27
+ --- !map:HashWithIndifferentAccess
28
+ key: "YOUR KEY"
29
+ secret: "YOUR SECRET"
30
+ token_cache: "token_cache.yml"
31
+
26
32
  == Authorization
27
33
 
28
34
  To authorise your application to access Flickr using your API key you will
@@ -32,6 +38,12 @@
32
38
  access it from your browser. Confirm the application has permission at
33
39
  the level you have specified.
34
40
 
41
+ Note that flickr has different types of keys. If you use one for a webapplication,
42
+ which is most likely, you need to define a callback and somehow make sure that
43
+ you connect the parameter :frob that flickr send via the callback is assigned
44
+ to the right user account. The best way to do this is to loop over all the current
45
+ user's flickr accounts and try flickr.auth.token with the :frob.
46
+
35
47
  Finally, cache the token (this will create the token cache file)
36
48
 
37
49
  If you have an invalid API key you will see errors such as:
@@ -44,7 +56,7 @@
44
56
  "98: Login failed / Invalid auth token" or
45
57
  "99: User not logged in / Insufficient permissions"
46
58
 
47
- == Authorization Example
59
+ == Authorization Example for non-webapplication
48
60
 
49
61
  require 'flickr_fu'
50
62
 
@@ -59,6 +71,28 @@
59
71
 
60
72
  flickr.auth.cache_token
61
73
 
74
+ == Authorization Example for a webapplication
75
+
76
+ flickr.auth.token also contains the nsid and username, this
77
+ example only stores the token and no other userdata.
78
+
79
+ require 'flickr_fu'
80
+ class FlickrController < ActionController::Base
81
+ def create
82
+ flickr = Flickr.new('flickr.yml')
83
+ redirect_to flickr.auth.url(:write)
84
+ end
85
+ def flickr_callback
86
+ flickr = Flickr.new('flickr.yml')
87
+ flickr.auth.frob = params[:frob]
88
+ current_user.update_attribute :flickr_token, flickr.auth.token.token
89
+ end
90
+ def something_else_with_flickr
91
+ flickr = Flickr.new(YAML.load_file('flickr.yml').merge(:token => current_user.flickr_token))
92
+ # now you have full access on the user's data :)
93
+ end
94
+ end
95
+
62
96
  == Search Example
63
97
 
64
98
  require 'flickr_fu'
@@ -108,3 +142,6 @@
108
142
  Mike Perham
109
143
  Chris Anderton
110
144
  Luke Francl
145
+ Thomas R. Koll
146
+ P. Mark Anderson
147
+ Josh Nichols
data/Rakefile CHANGED
@@ -1,22 +1,73 @@
1
1
  require 'rake'
2
- require 'rake/testtask'
3
2
  require 'rake/rdoctask'
4
-
5
- desc 'Default: run unit tests.'
6
- task :default => :test
7
-
8
- desc 'Test the contact_info plugin.'
9
- Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib'
11
- t.pattern = 'test/**/*_test.rb'
12
- t.verbose = true
3
+
4
+ # Gem building
5
+ begin
6
+ begin
7
+ require 'jeweler'
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ require 'jeweler'
11
+ end
12
+ Jeweler::Tasks.new do |s|
13
+ s.name = "flickr_fu"
14
+ s.summary = "Provides a ruby interface to flickr via the REST api"
15
+ s.email = "ben@commonthread.com"
16
+ s.homepage = "http://github.com/commonthread/flickr_fu"
17
+ s.description = "Provides a ruby interface to flickr via the REST api"
18
+ s.authors = ["Ben Wyrosdick", "Maciej Bilas"]
19
+ s.rdoc_options = ["--main", "README"]
20
+ s.extra_rdoc_files = ["README"]
21
+ s.add_dependency("mime-types", ["> 0.0.0"])
22
+ s.add_dependency("xml-magic", ["> 0.0.0"])
23
+ s.files.exclude("spec/spec.local.opts")
24
+ end
25
+ rescue LoadError
26
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
13
27
  end
14
-
15
- desc 'Generate documentation for the contact_info plugin.'
28
+
29
+ desc 'Generate documentation for flickr_fu.'
16
30
  Rake::RDocTask.new(:rdoc) do |rdoc|
17
31
  rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'ruby-flickr'
32
+ rdoc.title = 'flickr_fu'
19
33
  rdoc.options << '--line-numbers' << '--inline-source'
20
34
  rdoc.rdoc_files.include('README')
21
35
  rdoc.rdoc_files.include('lib/**/*.rb')
22
36
  end
37
+
38
+ # RSpec support
39
+ begin
40
+ require 'spec'
41
+ rescue LoadError
42
+ require 'rubygems'
43
+ require 'spec'
44
+ end
45
+ begin
46
+ require 'spec/rake/spectask'
47
+ rescue LoadError
48
+ puts <<-EOS
49
+ To use rspec for testing you must install rspec gem:
50
+ gem install rspec
51
+ EOS
52
+ exit(0)
53
+ end
54
+
55
+ task :default => :spec
56
+
57
+ spec_common = Proc.new do |t|
58
+ t.spec_opts = ['--options', "spec/spec.opts"]
59
+ t.spec_opts << ['--options', "spec/spec.local.opts" ] if File.exist?(File.dirname(__FILE__) + "/spec/spec.local.opts")
60
+ t.spec_files = FileList['spec/**/*_spec.rb']
61
+ end
62
+
63
+ desc "Run the specs under spec/models"
64
+ Spec::Rake::SpecTask.new do |t|
65
+ spec_common.call(t)
66
+ end
67
+
68
+ desc "Analyze code coverage with tests"
69
+ Spec::Rake::SpecTask.new("rcov") do |t|
70
+ spec_common.call(t)
71
+ t.rcov = true
72
+ t.rcov_opts = ["-x", "/var/lib", "-x", "spec/", "-T"]
73
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 3
4
+ :patch: 0
data/flickr_fu.gemspec CHANGED
@@ -1,35 +1,117 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  Gem::Specification.new do |s|
2
- s.name = "flickr_fu"
3
- s.version = "0.1.6"
4
- s.date = "2008-09-12"
5
- s.summary = "Provides a ruby interface to flickr via the REST api"
6
- s.email = "ben@commonthread.com"
7
- s.homepage = "http://github.com/commonthread/flickr_fu"
8
- s.description = "Provides a ruby interface to flickr via the REST api"
9
- s.has_rdoc = true
10
- s.authors = ["Ben Wyrosdick"]
11
- s.files = ["README",
12
- "LICENSE",
13
- "Rakefile",
14
- "flickr_fu.gemspec",
15
- "lib/flickr/auth.rb",
16
- "lib/flickr/base.rb",
17
- "lib/flickr/comment.rb",
18
- "lib/flickr/license.rb",
19
- "lib/flickr/note.rb",
20
- "lib/flickr/people.rb",
21
- "lib/flickr/person.rb",
22
- "lib/flickr/photo.rb",
23
- "lib/flickr/photo_response.rb",
24
- "lib/flickr/photos.rb",
25
- "lib/flickr/size.rb",
26
- "lib/flickr/status.rb",
27
- "lib/flickr/test.rb",
28
- "lib/flickr/token.rb",
29
- "lib/flickr/uploader.rb",
30
- "lib/flickr_fu.rb"]
4
+ s.name = %q{flickr_fu}
5
+ s.version = "0.3.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ben Wyrosdick", "Maciej Bilas"]
9
+ s.date = %q{2009-05-19}
10
+ s.description = %q{Provides a ruby interface to flickr via the REST api}
11
+ s.email = %q{ben@commonthread.com}
12
+ s.extra_rdoc_files = [
13
+ "README"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "LICENSE",
18
+ "README",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "flickr_fu.gemspec",
22
+ "lib/flickr/auth.rb",
23
+ "lib/flickr/base.rb",
24
+ "lib/flickr/comment.rb",
25
+ "lib/flickr/contact.rb",
26
+ "lib/flickr/contacts.rb",
27
+ "lib/flickr/errors.rb",
28
+ "lib/flickr/geo.rb",
29
+ "lib/flickr/license.rb",
30
+ "lib/flickr/location.rb",
31
+ "lib/flickr/note.rb",
32
+ "lib/flickr/people.rb",
33
+ "lib/flickr/person.rb",
34
+ "lib/flickr/photo.rb",
35
+ "lib/flickr/photo_response.rb",
36
+ "lib/flickr/photos.rb",
37
+ "lib/flickr/photoset.rb",
38
+ "lib/flickr/photosets.rb",
39
+ "lib/flickr/size.rb",
40
+ "lib/flickr/status.rb",
41
+ "lib/flickr/test.rb",
42
+ "lib/flickr/token.rb",
43
+ "lib/flickr/uploader.rb",
44
+ "lib/flickr/urls.rb",
45
+ "lib/flickr_fu.rb",
46
+ "spec/fixtures/flickr/contacts/get_list-fail-99.xml",
47
+ "spec/fixtures/flickr/contacts/get_public_list-0.xml",
48
+ "spec/fixtures/flickr/photos/geo/get_location-0.xml",
49
+ "spec/fixtures/flickr/photos/geo/get_location-fail-2.xml",
50
+ "spec/fixtures/flickr/photos/get_info-0.xml",
51
+ "spec/fixtures/flickr/photos/get_info-1.xml",
52
+ "spec/fixtures/flickr/photos/get_sizes-0.xml",
53
+ "spec/fixtures/flickr/photos/get_sizes-1.xml",
54
+ "spec/fixtures/flickr/photos/licenses/get_info.xml",
55
+ "spec/fixtures/flickr/photosets/get_list-0.xml",
56
+ "spec/fixtures/flickr/photosets/get_photos-0.xml",
57
+ "spec/fixtures/flickr/test/echo-0.xml",
58
+ "spec/fixtures/flickr/test/null-fail-99.xml",
59
+ "spec/fixtures/flickr/urls/get_group-0.xml",
60
+ "spec/fixtures/flickr/urls/get_group-fail-1.xml",
61
+ "spec/fixtures/flickr/urls/get_user_photos-0.xml",
62
+ "spec/fixtures/flickr/urls/get_user_photos-fail-1.xml",
63
+ "spec/fixtures/flickr/urls/get_user_photos-fail-2.xml",
64
+ "spec/fixtures/flickr/urls/get_user_profile-0.xml",
65
+ "spec/fixtures/flickr/urls/get_user_profile-fail-1.xml",
66
+ "spec/fixtures/flickr/urls/get_user_profile-fail-2.xml",
67
+ "spec/fixtures/flickr/urls/lookup_group-0.xml",
68
+ "spec/fixtures/flickr/urls/lookup_group-fail-1.xml",
69
+ "spec/fixtures/flickr/urls/lookup_user-0.xml",
70
+ "spec/fixtures/flickr/videos/get_info-0.xml",
71
+ "spec/fixtures/flickr/videos/get_sizes-0.xml",
72
+ "spec/flickr/base_spec.rb",
73
+ "spec/flickr/contacts_spec.rb",
74
+ "spec/flickr/errors_spec.rb",
75
+ "spec/flickr/geo_spec.rb",
76
+ "spec/flickr/photo_spec.rb",
77
+ "spec/flickr/photos_spec.rb",
78
+ "spec/flickr/photosets_spec.rb",
79
+ "spec/flickr/test_spec.rb",
80
+ "spec/flickr/urls_spec.rb",
81
+ "spec/spec.opts",
82
+ "spec/spec_helper.rb"
83
+ ]
84
+ s.homepage = %q{http://github.com/commonthread/flickr_fu}
31
85
  s.rdoc_options = ["--main", "README"]
32
- s.extra_rdoc_files = ["README"]
33
- s.add_dependency("mime-types", ["> 0.0.0"])
34
- s.add_dependency("xml-magic", ["> 0.0.0"])
86
+ s.require_paths = ["lib"]
87
+ s.rubygems_version = %q{1.3.3}
88
+ s.summary = %q{Provides a ruby interface to flickr via the REST api}
89
+ s.test_files = [
90
+ "spec/spec_helper.rb",
91
+ "spec/flickr/test_spec.rb",
92
+ "spec/flickr/geo_spec.rb",
93
+ "spec/flickr/contacts_spec.rb",
94
+ "spec/flickr/urls_spec.rb",
95
+ "spec/flickr/errors_spec.rb",
96
+ "spec/flickr/base_spec.rb",
97
+ "spec/flickr/photo_spec.rb",
98
+ "spec/flickr/photosets_spec.rb",
99
+ "spec/flickr/photos_spec.rb"
100
+ ]
101
+
102
+ if s.respond_to? :specification_version then
103
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
104
+ s.specification_version = 3
105
+
106
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
107
+ s.add_runtime_dependency(%q<mime-types>, ["> 0.0.0"])
108
+ s.add_runtime_dependency(%q<xml-magic>, ["> 0.0.0"])
109
+ else
110
+ s.add_dependency(%q<mime-types>, ["> 0.0.0"])
111
+ s.add_dependency(%q<xml-magic>, ["> 0.0.0"])
112
+ end
113
+ else
114
+ s.add_dependency(%q<mime-types>, ["> 0.0.0"])
115
+ s.add_dependency(%q<xml-magic>, ["> 0.0.0"])
116
+ end
35
117
  end
data/lib/flickr/auth.rb CHANGED
@@ -7,6 +7,11 @@ class Flickr::Auth < Flickr::Base
7
7
  def frob
8
8
  @frob ||= get_frob
9
9
  end
10
+
11
+ # set the frob
12
+ def frob= frob
13
+ @frob=frob
14
+ end
10
15
 
11
16
  # generates the authorization url to allow access to a flickr account.
12
17
  #
@@ -58,7 +63,9 @@ class Flickr::Auth < Flickr::Base
58
63
  end
59
64
 
60
65
  def get_token(pass_through)
61
- if @flickr.token_cache and File.exists?(@flickr.token_cache)
66
+ if @flickr.token
67
+ @flickr.token
68
+ elsif @flickr.token_cache and File.exists?(@flickr.token_cache)
62
69
  YAML.load_file(@flickr.token_cache)
63
70
  elsif pass_through
64
71
  rsp = @flickr.send_request('flickr.auth.getToken', {:frob => self.frob})
data/lib/flickr/base.rb CHANGED
@@ -4,7 +4,7 @@ module Flickr
4
4
  end
5
5
 
6
6
  class Base
7
- attr_reader :api_key, :api_secret, :token_cache
7
+ attr_reader :api_key, :api_secret, :token_cache, :token
8
8
 
9
9
  REST_ENDPOINT = 'http://api.flickr.com/services/rest/'
10
10
  AUTH_ENDPOINT = 'http://flickr.com/services/auth/'
@@ -12,30 +12,62 @@ module Flickr
12
12
 
13
13
  # create a new flickr object
14
14
  #
15
- # Params
15
+ # You can either pass a hash with the following attributes:
16
+ #
17
+ # * :key (Required)
18
+ # the API key
19
+ # * :secret (Required)
20
+ # the API secret
21
+ # * :token (Optional)
22
+ # Flickr::Auth::Token object
23
+ #
24
+ # or:
25
+ #
16
26
  # * config_file (Required)
17
27
  # yaml file to load configuration from
18
- # * token_cache (Optional)
19
- # location of the token cache file. This will override the setting in the config file
20
- #
28
+ # * options (Optional)
29
+ # hash containing any of the two options
30
+ # * token_cache
31
+ # location of the token cache file. This will override the setting in the config file
32
+ # * environment
33
+ # section in the config file that flickr_fu should look for the API key and secret
34
+ # Useful when using with Rails
35
+ #
21
36
  # Config Example (yaml file)
22
- #
23
37
  # ---
24
- # key: YOUR_API_KEY
25
- # secret: YOUR_API_SECRET
26
- # token_cache: token.yml
27
- #
28
- def initialize(config_file, token_cache = nil)
29
- config = YAML.load_file(config_file)
30
-
31
- @api_key = config['key']
32
- @api_secret = config['secret']
33
- @token_cache = token_cache || config['token_cache']
34
-
35
- raise 'flickr config file must contain an api key and secret' unless @api_key and @api_secret
38
+ # key: YOUR_API_KEY
39
+ # secret: YOUR_API_SECRET
40
+ # token_cache: token.yml
41
+ #
42
+ # Example config file with two environments:
43
+ # ---
44
+ # development:
45
+ # key: YOUR_DEVELOPMENT_API_KEY
46
+ # secret: YOUR_DEVELOPMENT_API_SECRET
47
+ # production:
48
+ # key: YOUR_PRODUCTION_API_KEY
49
+ # secret: YOUR_PRODUCTION_API_SECRET
50
+ def initialize(config_param, options_param = {})
51
+ if options_param.is_a? String
52
+ options = {:token_cache => options_param}
53
+ else
54
+ options = options_param
55
+ end
56
+ if config_param.is_a? String
57
+ config = YAML.load_file(config_param)
58
+ config = config[options[:environment]] if options.has_key? :environment
59
+ else
60
+ config = config_param
61
+ end
62
+ @api_key = config[:key] || config["key"]
63
+ @api_secret = config[:secret] || config["secret"]
64
+ @token_cache = options[:token_cache] || config["token_cache"]
65
+ @token = config[:token] || options[:token]
66
+ raise 'config file must contain an api key and secret' unless @api_key and @api_secret
67
+ raise 'you cannot specify both the token and token_cache' if @token and @token_cache
36
68
  end
37
69
 
38
- # sends a request to the flcikr REST api
70
+ # sends a request to the flickr REST api
39
71
  #
40
72
  # Params
41
73
  # * method (Required)
@@ -53,12 +85,7 @@ module Flickr
53
85
  options.merge!(:api_key => @api_key, :method => method)
54
86
  sign_request(options)
55
87
 
56
- if http_method == :get
57
- api_call = endpoint + "?" + options.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
58
- rsp = Net::HTTP.get(URI.parse(api_call))
59
- else
60
- rsp = Net::HTTP.post_form(URI.parse(endpoint), options).body
61
- end
88
+ rsp = request_over_http(options, http_method, endpoint)
62
89
 
63
90
  rsp = '<rsp stat="ok"></rsp>' if rsp == ""
64
91
  xm = XmlMagic.new(rsp)
@@ -66,7 +93,7 @@ module Flickr
66
93
  if xm[:stat] == 'ok'
67
94
  xm
68
95
  else
69
- raise "#{xm.err[:code]}: #{xm.err[:msg]}"
96
+ raise Flickr::Errors.error_for(xm.err[:code].to_i, xm.err[:msg])
70
97
  end
71
98
  end
72
99
 
@@ -90,6 +117,9 @@ module Flickr
90
117
  # creates and/or returns the Flickr::Photos object
91
118
  def photos() @photos ||= Flickr::Photos.new(self) end
92
119
 
120
+ # creates and/or returns the Flickr::Photos object
121
+ def photosets() @photosets ||= Flickr::Photosets.new(self) end
122
+
93
123
  # creates and/or returns the Flickr::People object
94
124
  def people() @people ||= Flickr::People.new(self) end
95
125
 
@@ -98,5 +128,24 @@ module Flickr
98
128
 
99
129
  # creates and/or returns the Flickr::Uploader object
100
130
  def uploader() @uploader ||= Flickr::Uploader.new(self) end
131
+
132
+ # creates and/or returns the Flickr::Contacts object
133
+ def contacts() @contacts ||= Flickr::Contacts.new(self) end
134
+
135
+ # creates and/or returns the Flickr::Urls object
136
+ def urls() @urls ||= Flickr::Urls.new(self) end
137
+
138
+ protected
139
+
140
+ # For easier testing. You can mock this method with a XML file you're expecting to receive
141
+ def request_over_http(options, http_method, endpoint)
142
+ if http_method == :get
143
+ api_call = endpoint + "?" + options.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
144
+ Net::HTTP.get(URI.parse(api_call))
145
+ else
146
+ Net::HTTP.post_form(URI.parse(endpoint), options).body
147
+ end
148
+ end
149
+
101
150
  end
102
151
  end