reagent-fleakr 0.3.0 → 0.4.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 (51) hide show
  1. data/README.rdoc +115 -20
  2. data/Rakefile +1 -1
  3. data/lib/fleakr.rb +66 -7
  4. data/lib/fleakr/api.rb +7 -0
  5. data/lib/fleakr/api/file_parameter.rb +47 -0
  6. data/lib/fleakr/api/method_request.rb +57 -0
  7. data/lib/fleakr/api/parameter.rb +35 -0
  8. data/lib/fleakr/api/parameter_list.rb +96 -0
  9. data/lib/fleakr/api/response.rb +2 -2
  10. data/lib/fleakr/api/upload_request.rb +64 -0
  11. data/lib/fleakr/api/value_parameter.rb +36 -0
  12. data/lib/fleakr/core_ext.rb +1 -0
  13. data/lib/fleakr/core_ext/hash.rb +22 -0
  14. data/lib/fleakr/objects.rb +9 -0
  15. data/lib/fleakr/objects/authentication_token.rb +43 -0
  16. data/lib/fleakr/objects/contact.rb +5 -5
  17. data/lib/fleakr/objects/error.rb +2 -2
  18. data/lib/fleakr/objects/group.rb +2 -2
  19. data/lib/fleakr/objects/image.rb +7 -7
  20. data/lib/fleakr/objects/photo.rb +69 -5
  21. data/lib/fleakr/objects/search.rb +3 -6
  22. data/lib/fleakr/objects/set.rb +11 -5
  23. data/lib/fleakr/objects/user.rb +14 -26
  24. data/lib/fleakr/support.rb +2 -0
  25. data/lib/fleakr/support/attribute.rb +30 -12
  26. data/lib/fleakr/support/object.rb +20 -4
  27. data/lib/fleakr/version.rb +1 -1
  28. data/test/fixtures/auth.checkToken.xml +8 -0
  29. data/test/fixtures/auth.getFullToken.xml +8 -0
  30. data/test/fixtures/people.getInfo.xml +1 -1
  31. data/test/fixtures/photos.getInfo.xml +20 -0
  32. data/test/test_helper.rb +18 -3
  33. data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
  34. data/test/unit/fleakr/api/method_request_test.rb +103 -0
  35. data/test/unit/fleakr/api/parameter_list_test.rb +161 -0
  36. data/test/unit/fleakr/api/parameter_test.rb +34 -0
  37. data/test/unit/fleakr/api/upload_request_test.rb +133 -0
  38. data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
  39. data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
  40. data/test/unit/fleakr/objects/authentication_token_test.rb +47 -0
  41. data/test/unit/fleakr/objects/image_test.rb +10 -5
  42. data/test/unit/fleakr/objects/photo_test.rb +96 -36
  43. data/test/unit/fleakr/objects/search_test.rb +1 -1
  44. data/test/unit/fleakr/objects/set_test.rb +12 -1
  45. data/test/unit/fleakr/objects/user_test.rb +2 -16
  46. data/test/unit/fleakr/support/attribute_test.rb +82 -24
  47. data/test/unit/fleakr/support/object_test.rb +26 -3
  48. data/test/unit/fleakr_test.rb +65 -6
  49. metadata +27 -4
  50. data/lib/fleakr/api/request.rb +0 -58
  51. data/test/unit/fleakr/api/request_test.rb +0 -93
@@ -9,13 +9,10 @@ module Fleakr
9
9
 
10
10
  # Retrieve search results from the API
11
11
  def results
12
- if @results.nil?
13
- response = Fleakr::Api::Request.with_response!('photos.search', parameters)
14
- @results = (response.body/'rsp/photos/photo').map do |flickr_photo|
15
- Photo.new(flickr_photo)
16
- end
12
+ @results ||= begin
13
+ response = Fleakr::Api::MethodRequest.with_response!('photos.search', parameters)
14
+ (response.body/'rsp/photos/photo').map {|p| Photo.new(p) }
17
15
  end
18
- @results
19
16
  end
20
17
 
21
18
  private
@@ -8,6 +8,7 @@ module Fleakr
8
8
  # [id] The ID for this photoset
9
9
  # [title] The title of this photoset
10
10
  # [description] The description of this set
11
+ # [count] Count of photos in this set
11
12
  #
12
13
  # == Associations
13
14
  #
@@ -19,26 +20,31 @@ module Fleakr
19
20
 
20
21
  has_many :photos, :using => :photoset_id
21
22
 
22
- flickr_attribute :id, :attribute => 'id'
23
+ flickr_attribute :id
23
24
  flickr_attribute :title
24
25
  flickr_attribute :description
26
+ flickr_attribute :count, :from => '@photos'
25
27
 
26
28
  find_all :by_user_id, :call => 'photosets.getList', :path => 'photosets/photoset'
27
29
 
28
- # Save all photos in this set to the specified directory using the specified size. Allowed
30
+ # Save all photos in this set to the specified directory for the specified size. Allowed
29
31
  # Sizes include <tt>:square</tt>, <tt>:small</tt>, <tt>:thumbnail</tt>, <tt>:medium</tt>,
30
- # <tt>:large</tt>, and <tt>:original</tt>. When saving the set, this # method will create
32
+ # <tt>:large</tt>, and <tt>:original</tt>. When saving the set, this method will create
31
33
  # a subdirectory based on the set's title.
32
34
  #
33
35
  def save_to(path, size)
34
36
  target = "#{path}/#{self.title}"
35
37
  FileUtils.mkdir(target) unless File.exist?(target)
36
38
 
37
- self.photos.each do |photo|
39
+ self.photos.each_with_index do |photo, index|
38
40
  image = photo.send(size)
39
- image.save_to(target) unless image.nil?
41
+ image.save_to(target, file_prefix(index)) unless image.nil?
40
42
  end
41
43
  end
44
+
45
+ def file_prefix(index) # :nodoc:
46
+ sprintf("%0#{self.count.length}d_", (index + 1))
47
+ end
42
48
 
43
49
  end
44
50
  end
@@ -11,6 +11,7 @@ module Fleakr
11
11
  # [id] The ID for this user (also referred to as the NSID in the API docs)
12
12
  # [username] This user's username
13
13
  # [name] This user's full name (if entered)
14
+ # [location] This user's location (if entered)
14
15
  # [photos_url] The direct URL to this user's photostream
15
16
  # [profile_url] The direct URL to this user's profile
16
17
  # [photos_count] The number of photos that this user has uploaded
@@ -42,37 +43,24 @@ module Fleakr
42
43
 
43
44
  include Fleakr::Support::Object
44
45
 
45
- def self.lazily_load(*attributes)
46
- options = attributes.extract_options!
47
-
48
- attributes.each do |attribute|
49
- class_eval <<-CODE
50
- def #{attribute}_with_loading
51
- self.send(:#{options[:with]}) if @#{attribute}.nil?
52
- #{attribute}_without_loading
53
- end
54
- alias_method_chain :#{attribute}, :loading
55
- CODE
56
- end
57
- end
58
-
59
- flickr_attribute :id, :xpath => 'rsp/user', :attribute => 'nsid'
60
- flickr_attribute :username, :xpath => 'rsp/user/username'
61
- flickr_attribute :name, :xpath => 'rsp/person/realname'
62
- flickr_attribute :photos_url, :xpath => 'rsp/person/photosurl'
63
- flickr_attribute :profile_url, :xpath => 'rsp/person/profileurl'
64
- flickr_attribute :photos_count, :xpath => 'rsp/person/photos/count'
65
- flickr_attribute :icon_server, :xpath => 'rsp/person', :attribute => 'iconserver'
66
- flickr_attribute :icon_farm, :xpath => 'rsp/person', :attribute => 'iconfarm'
67
- flickr_attribute :pro, :xpath => 'rsp/person', :attribute => 'ispro'
68
- flickr_attribute :admin, :xpath => 'rsp/person', :attribute => 'isadmin'
46
+ flickr_attribute :id, :from => 'user@nsid'
47
+ flickr_attribute :username
48
+ flickr_attribute :name, :from => 'person/realname'
49
+ flickr_attribute :location
50
+ flickr_attribute :photos_url, :from => 'person/photosurl'
51
+ flickr_attribute :profile_url, :from => 'person/profileurl'
52
+ flickr_attribute :photos_count, :from => 'person/photos/count'
53
+ flickr_attribute :icon_server, :from => 'person@iconserver'
54
+ flickr_attribute :icon_farm, :from => 'person@iconfarm'
55
+ flickr_attribute :pro, :from => 'person@ispro'
56
+ flickr_attribute :admin, :from => 'person@isadmin'
69
57
 
70
58
  has_many :sets, :groups, :photos, :contacts
71
59
 
72
60
  find_one :by_username, :call => 'people.findByUsername'
73
61
  find_one :by_email, :using => :find_email, :call => 'people.findByEmail'
74
62
 
75
- lazily_load :name, :photos_url, :profile_url, :photos_count, :with => :load_info
63
+ lazily_load :name, :photos_url, :profile_url, :photos_count, :location, :with => :load_info
76
64
  lazily_load :icon_server, :icon_farm, :pro, :admin, :with => :load_info
77
65
 
78
66
  scoped_search
@@ -97,7 +85,7 @@ module Fleakr
97
85
  end
98
86
 
99
87
  def load_info # :nodoc:
100
- response = Fleakr::Api::Request.with_response!('people.getInfo', :user_id => self.id)
88
+ response = Fleakr::Api::MethodRequest.with_response!('people.getInfo', :user_id => self.id)
101
89
  self.populate_from(response.body)
102
90
  end
103
91
 
@@ -0,0 +1,2 @@
1
+ require 'fleakr/support/attribute'
2
+ require 'fleakr/support/object'
@@ -2,25 +2,43 @@ module Fleakr
2
2
  module Support # :nodoc:all
3
3
  class Attribute
4
4
 
5
- attr_reader :name, :xpath, :attribute
5
+ # TODO: Refactor the location / attribute logic into a Source class
6
6
 
7
- def initialize(name, options = {})
7
+ attr_reader :name, :sources
8
+
9
+ def initialize(name, sources = nil)
8
10
  @name = name.to_sym
9
- @attribute = options[:attribute]
11
+
12
+ @sources = Array(sources)
13
+ @sources << @name.to_s if @sources.empty?
14
+ end
15
+
16
+ def split(source)
17
+ location, attribute = source.split('@')
18
+ location = self.name.to_s if location.blank?
19
+
20
+ [location, attribute]
21
+ end
22
+
23
+ def node_for(document, source)
24
+ document.at(location(source)) || document.search("//[@#{attribute(source)}]").first
25
+ end
10
26
 
11
- @xpath = options[:xpath]
12
- @xpath ||= @name.to_s unless @attribute
27
+ def attribute(source)
28
+ location, attribute = source.split('@')
29
+ attribute || location
30
+ end
31
+
32
+ def location(source)
33
+ split(source).first
13
34
  end
14
35
 
15
36
  def value_from(document)
16
- node = document
17
-
18
- begin
19
- node = document.at(self.xpath) if self.xpath
20
- self.attribute.nil? ? node.inner_text : node[self.attribute]
21
- rescue NoMethodError
22
- nil
37
+ values = sources.map do |source|
38
+ node = node_for(document, source)
39
+ (node.attributes[attribute(source)] || node.inner_text) unless node.nil?
23
40
  end
41
+ values.compact.first
24
42
  end
25
43
 
26
44
  end
@@ -9,7 +9,7 @@ module Fleakr
9
9
  end
10
10
 
11
11
  def flickr_attribute(name, options = {})
12
- self.attributes << Attribute.new(name, options)
12
+ self.attributes << Attribute.new(name, options[:from])
13
13
  class_eval "attr_accessor :#{name}"
14
14
  end
15
15
 
@@ -34,7 +34,7 @@ module Fleakr
34
34
 
35
35
  class_eval <<-CODE
36
36
  def self.find_all_#{condition}(value)
37
- response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
37
+ response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', :#{attribute} => value)
38
38
  (response.body/'rsp/#{options[:path]}').map {|e| #{target_class}.new(e) }
39
39
  end
40
40
  CODE
@@ -44,8 +44,10 @@ module Fleakr
44
44
  attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
45
45
 
46
46
  class_eval <<-CODE
47
- def self.find_#{condition}(value)
48
- response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
47
+ def self.find_#{condition}(value, options = {})
48
+ options.merge!(:#{attribute} => value)
49
+
50
+ response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', options)
49
51
  #{self.name}.new(response.body)
50
52
  end
51
53
  CODE
@@ -60,6 +62,20 @@ module Fleakr
60
62
  end
61
63
  CODE
62
64
  end
65
+
66
+ def lazily_load(*attributes)
67
+ options = attributes.extract_options!
68
+
69
+ attributes.each do |attribute|
70
+ class_eval <<-CODE
71
+ def #{attribute}_with_loading
72
+ self.send(:#{options[:with]}) if @#{attribute}.nil?
73
+ #{attribute}_without_loading
74
+ end
75
+ alias_method_chain :#{attribute}, :loading
76
+ CODE
77
+ end
78
+ end
63
79
 
64
80
  end
65
81
 
@@ -2,7 +2,7 @@ module Fleakr
2
2
  module Version # :nodoc:
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 3
5
+ MINOR = 4
6
6
  TINY = 0
7
7
 
8
8
  def self.to_s
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rsp stat="ok">
3
+ <auth>
4
+ <token>abc-123</token>
5
+ <perms>delete</perms>
6
+ <user nsid="31066442@N69" fullname="Sir Froot Pants" username="frootpantz"></user>
7
+ </auth>
8
+ </rsp>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rsp stat="ok">
3
+ <auth>
4
+ <token>abc-123</token>
5
+ <perms>delete</perms>
6
+ <user nsid="31066442@N69" fullname="Sir Froot Pants" username="frootpantz"></user>
7
+ </auth>
8
+ </rsp>
@@ -4,7 +4,7 @@
4
4
  <username>frootpantz</username>
5
5
  <realname>Sir Froot Pantz</realname>
6
6
  <mbox_sha1sum>e52ed1e5b91c763694995460e9796fc2adc02019</mbox_sha1sum>
7
- <location />
7
+ <location>The Moon</location>
8
8
  <photosurl>http://www.flickr.com/photos/frootpantz/</photosurl>
9
9
  <profileurl>http://www.flickr.com/people/frootpantz/</profileurl>
10
10
  <mobileurl>http://m.flickr.com/photostream.gne?id=34225</mobileurl>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photo id="1" secret="secret" server="3085" farm="4" dateuploaded="1230274722" isfavorite="0" license="0" rotation="0" originalsecret="sekrit" originalformat="jpg" media="photo">
4
+ <owner nsid="31066442@N69" username="frootpantz" realname="" location="" />
5
+ <title>Tree</title>
6
+ <description>A Tree</description>
7
+ <visibility ispublic="1" isfriend="0" isfamily="0" />
8
+ <dates posted="1230274722" taken="2008-12-25 18:26:55" takengranularity="0" lastupdate="1230276652" />
9
+
10
+ <editability cancomment="0" canaddmeta="0" />
11
+ <usage candownload="1" canblog="0" canprint="0" />
12
+ <comments>0</comments>
13
+ <notes />
14
+ <tags />
15
+ <urls>
16
+ <url type="photopage">http://www.flickr.com/photos/yes/1</url>
17
+ </urls>
18
+
19
+ </photo>
20
+ </rsp>
data/test/test_helper.rb CHANGED
@@ -9,6 +9,19 @@ require File.dirname(__FILE__) + '/../lib/fleakr'
9
9
 
10
10
  class Test::Unit::TestCase
11
11
 
12
+ def self.should_autoload_when_accessing(*attributes)
13
+ options = attributes.extract_options!
14
+ attributes.each do |accessor_name|
15
+ it "should load the additional user information when accessing the :#{accessor_name} attribute" do
16
+ klass = self.class.name.sub(/Test$/, '').constantize
17
+
18
+ object = klass.new
19
+ object.expects(options[:with]).with()
20
+ object.send(accessor_name)
21
+ end
22
+ end
23
+ end
24
+
12
25
  def self.should_have_a_value_for(attribute_test)
13
26
  it "should have a value for :#{attribute_test.keys.first}" do
14
27
  @object.send(attribute_test.keys.first).should == attribute_test.values.first
@@ -64,12 +77,14 @@ class Test::Unit::TestCase
64
77
  klass = "Fleakr::Objects::#{class_name}".constantize
65
78
  object_type = class_name.downcase
66
79
 
80
+ condition_value = '1'
81
+
67
82
  options[:with] = options[:by] if options[:with].nil?
83
+ params = {options[:with] => condition_value}
68
84
 
69
85
  it "should be able to find a #{thing} by #{options[:by]}" do
70
- condition_value = '1'
71
86
  stub = stub()
72
- response = mock_request_cycle :for => options[:call], :with => {options[:with] => condition_value}
87
+ response = mock_request_cycle :for => options[:call], :with => params
73
88
 
74
89
  klass.expects(:new).with(response.body).returns(stub)
75
90
  klass.send("find_by_#{options[:by]}".to_sym, condition_value).should == stub
@@ -108,7 +123,7 @@ class Test::Unit::TestCase
108
123
 
109
124
  def mock_request_cycle(options)
110
125
  response = stub(:body => Hpricot.XML(read_fixture(options[:for])))
111
- Fleakr::Api::Request.expects(:with_response!).with(options[:for], options[:with]).returns(response)
126
+ Fleakr::Api::MethodRequest.expects(:with_response!).with(options[:for], options[:with]).returns(response)
112
127
 
113
128
  response
114
129
  end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Api
4
+ class FileParameterTest < Test::Unit::TestCase
5
+
6
+ describe "An instance of the FileParameter class" do
7
+
8
+ before do
9
+ @temp_dir = File.expand_path(create_temp_directory)
10
+ @filename = "#{@temp_dir}/image.jpg"
11
+ end
12
+
13
+ after do
14
+ FileUtils.rm_rf(@temp_dir)
15
+ end
16
+
17
+ it "should know not to include itself in the parameter signature" do
18
+ parameter = FileParameter.new('photo', @filename)
19
+ parameter.include_in_signature?.should be(false)
20
+ end
21
+
22
+ {'jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif'}.each do |ext, mime_type|
23
+ it "should know the correct MIME type for an extension of #{ext}" do
24
+ parameter = FileParameter.new('photo', "#{@temp_dir}/image.#{ext}")
25
+ parameter.mime_type.should == mime_type
26
+ end
27
+ end
28
+
29
+ it "should retrieve the contents of the file when accessing the value" do
30
+ File.expects(:read).with(@filename).returns('bopbip')
31
+
32
+ parameter = FileParameter.new('photo', @filename)
33
+ parameter.value.should == 'bopbip'
34
+ end
35
+
36
+ it "should cache the file contents after retrieving them" do
37
+ File.expects(:read).with(@filename).once.returns('bopbip')
38
+
39
+ parameter = FileParameter.new('photo', @filename)
40
+ 2.times { parameter.value }
41
+ end
42
+
43
+ it "should know how to generate a form representation of itself" do
44
+ filename = 'image.jpg'
45
+ mime_type = 'image/jpeg'
46
+
47
+ parameter = FileParameter.new('photo', filename)
48
+ parameter.stubs(:mime_type).with().returns(mime_type)
49
+ parameter.stubs(:value).with().returns('data')
50
+
51
+ expected =
52
+ "Content-Disposition: form-data; name=\"photo\"; filename=\"#{filename}\"\r\n" +
53
+ "Content-Type: image/jpeg\r\n" +
54
+ "\r\n" +
55
+ "data\r\n"
56
+
57
+ parameter.to_form.should == expected
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Api
4
+ class MethodRequestTest < Test::Unit::TestCase
5
+
6
+ describe "An instance of MethodRequest" do
7
+
8
+ context "with API credentials" do
9
+
10
+ before do
11
+ @api_key = 'f00b4r'
12
+ Fleakr.stubs(:api_key).with().returns(@api_key)
13
+ Fleakr.stubs(:shared_secret).with().returns('sekrit')
14
+ end
15
+
16
+ it "should know the full query parameters" do
17
+ request = MethodRequest.new('flickr.people.findByUsername', :username => 'foobar')
18
+
19
+ request.parameters[:api_key].value.should == @api_key
20
+ request.parameters[:method].value.should == 'flickr.people.findByUsername'
21
+ request.parameters[:username].value.should == 'foobar'
22
+ end
23
+
24
+ it "should translate a shorthand API call" do
25
+ request = MethodRequest.new('people.findByUsername')
26
+ request.parameters[:method].value.should == 'flickr.people.findByUsername'
27
+ end
28
+
29
+ it "should know that it needs to sign the request" do
30
+ ParameterList.expects(:new).with(:sign? => true).returns(stub(:<< => nil))
31
+ request = MethodRequest.new('people.findByUsername', :sign? => true)
32
+ end
33
+
34
+ it "should know that it needs to authenticate the request" do
35
+ ParameterList.expects(:new).with(:authenticate? => true).returns(stub(:<< => nil))
36
+ request = MethodRequest.new('activity.userPhotos', :authenticate? => true)
37
+ end
38
+
39
+ it "should know the endpoint with full parameters" do
40
+ query_parameters = 'foo=bar'
41
+
42
+ request = MethodRequest.new('people.getInfo')
43
+ request.parameters.stubs(:to_query).returns(query_parameters)
44
+
45
+ uri_mock = mock() {|m| m.expects(:query=).with(query_parameters)}
46
+ URI.expects(:parse).with("http://api.flickr.com/services/rest/").returns(uri_mock)
47
+
48
+ request.__send__(:endpoint_uri).should == uri_mock
49
+ end
50
+
51
+ it "should be able to make a request" do
52
+ endpoint_uri = stub()
53
+
54
+ request = MethodRequest.new('people.findByUsername')
55
+ request.stubs(:endpoint_uri).with().returns(endpoint_uri)
56
+
57
+ Net::HTTP.expects(:get).with(endpoint_uri).returns('<xml>')
58
+
59
+ request.send
60
+ end
61
+
62
+ it "should create a response from the request" do
63
+ response_xml = '<xml>'
64
+ response_stub = stub()
65
+
66
+ Net::HTTP.stubs(:get).returns(response_xml)
67
+ Response.expects(:new).with(response_xml).returns(response_stub)
68
+
69
+ request = MethodRequest.new('people.findByUsername')
70
+ request.stubs(:endpoint_uri)
71
+
72
+ request.send.should == response_stub
73
+ end
74
+
75
+ it "should be able to make a full request and response cycle" do
76
+ method = 'flickr.people.findByUsername'
77
+ params = {:username => 'foobar'}
78
+
79
+ response = stub(:error? => false)
80
+
81
+ MethodRequest.expects(:new).with(method, params).returns(stub(:send => response))
82
+
83
+ MethodRequest.with_response!(method, params).should == response
84
+ end
85
+
86
+ it "should raise an exception when the full request / response cycle has errors" do
87
+ method = 'flickr.people.findByUsername'
88
+ params = {:username => 'foobar'}
89
+
90
+ response = stub(:error? => true, :error => stub(:code => '1', :message => 'User not found'))
91
+
92
+ MethodRequest.expects(:new).with(method, params).returns(stub(:send => response))
93
+
94
+ lambda do
95
+ MethodRequest.with_response!('flickr.people.findByUsername', :username => 'foobar')
96
+ end.should raise_error(Fleakr::ApiError)
97
+ end
98
+
99
+ end
100
+ end
101
+
102
+ end
103
+ end