zuck 0.0.4

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 (52) hide show
  1. data/.rvmrc +1 -0
  2. data/.travis.yml +7 -0
  3. data/.yardopts +4 -0
  4. data/CHANGELOG.markdown +4 -0
  5. data/Gemfile +35 -0
  6. data/Gemfile.lock +110 -0
  7. data/Guardfile.dist +45 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.markdown +138 -0
  10. data/Rakefile +39 -0
  11. data/VERSION +1 -0
  12. data/console +26 -0
  13. data/lib/zuck/facebook/ad_account.rb +40 -0
  14. data/lib/zuck/facebook/ad_campaign.rb +24 -0
  15. data/lib/zuck/facebook/ad_creative.rb +30 -0
  16. data/lib/zuck/facebook/ad_group.rb +39 -0
  17. data/lib/zuck/facebook/targeting_spec.rb +200 -0
  18. data/lib/zuck/fb_object/dsl.rb +110 -0
  19. data/lib/zuck/fb_object/error.rb +8 -0
  20. data/lib/zuck/fb_object/hash_delegator.rb +111 -0
  21. data/lib/zuck/fb_object/helpers.rb +57 -0
  22. data/lib/zuck/fb_object/read.rb +147 -0
  23. data/lib/zuck/fb_object/read_only.rb +0 -0
  24. data/lib/zuck/fb_object/write.rb +75 -0
  25. data/lib/zuck/fb_object.rb +53 -0
  26. data/lib/zuck/koala/koala_methods.rb +27 -0
  27. data/lib/zuck.rb +9 -0
  28. data/spec/fixtures/a_single_account.yml +75 -0
  29. data/spec/fixtures/a_single_campaign.yml +48 -0
  30. data/spec/fixtures/create_ad_campaign.yml +49 -0
  31. data/spec/fixtures/create_ad_group.yml +47 -0
  32. data/spec/fixtures/delete_ad_group.yml +50 -0
  33. data/spec/fixtures/find_a_single_campaign_and_update_it.yml +247 -0
  34. data/spec/fixtures/list_of_ad_accounts.yml +75 -0
  35. data/spec/fixtures/list_of_ad_campaigns.yml +76 -0
  36. data/spec/fixtures/list_of_ad_creatives.yml +51 -0
  37. data/spec/fixtures/list_of_ad_groups.yml +49 -0
  38. data/spec/fixtures/list_of_all_ad_creatives_of_account.yml +86 -0
  39. data/spec/fixtures/reach_for_invalid_keyword.yml +95 -0
  40. data/spec/fixtures/reach_for_valid_keywords.yml +93 -0
  41. data/spec/fixtures/reach_for_valid_keywords_male_young.yml +93 -0
  42. data/spec/lib/zuck/facebook/ad_account_spec.rb +26 -0
  43. data/spec/lib/zuck/facebook/ad_campaign_spec.rb +4 -0
  44. data/spec/lib/zuck/facebook/targeting_spec_spec.rb +174 -0
  45. data/spec/lib/zuck/fb_object/helpers_spec.rb +67 -0
  46. data/spec/lib/zuck/koala/koala_methods_spec.rb +30 -0
  47. data/spec/lib/zuck/util/hash_delegator_spec.rb +54 -0
  48. data/spec/lib/zuck_spec.rb +165 -0
  49. data/spec/spec_helper.rb +47 -0
  50. data/spec/vcr_setup.rb +15 -0
  51. data/zuck.gemspec +141 -0
  52. metadata +389 -0
@@ -0,0 +1,95 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=eminem,invalidsssssssssssssss&type=adkeywordvalid
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - ! '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Access-Control-Allow-Origin:
22
+ - ! '*'
23
+ Cache-Control:
24
+ - private, no-cache, no-store, must-revalidate
25
+ Content-Type:
26
+ - text/javascript; charset=UTF-8
27
+ Etag:
28
+ - ! '"1b6af91a08d48aeee5ffa0cf3437f38b61281b68"'
29
+ Expires:
30
+ - Sat, 01 Jan 2000 00:00:00 GMT
31
+ Pragma:
32
+ - no-cache
33
+ X-Fb-Rev:
34
+ - '698469'
35
+ X-Fb-Debug:
36
+ - 7so4yUGhkG2hb0KiZDAFNlrgtEmcB0xQ9Xilxl/LfRw=
37
+ Date:
38
+ - Wed, 19 Dec 2012 14:36:48 GMT
39
+ Connection:
40
+ - keep-alive
41
+ Content-Length:
42
+ - '108'
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ! '{"data":[{"name":"Eminem","valid":true,"id":6003170652434},{"name":"invalidsssssssssssssss","valid":false}]}'
46
+ http_version:
47
+ recorded_at: Wed, 19 Dec 2012 14:36:48 GMT
48
+ - request:
49
+ method: get
50
+ uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22eminem%22,%22invalidsssssssssssssss%22%5D,%22age_min%22:13,%22connections%22:%5B%5D%7D
51
+ body:
52
+ encoding: US-ASCII
53
+ string: ''
54
+ headers:
55
+ Accept-Encoding:
56
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
57
+ Accept:
58
+ - ! '*/*'
59
+ User-Agent:
60
+ - Ruby
61
+ response:
62
+ status:
63
+ code: 400
64
+ message: Bad Request
65
+ headers:
66
+ Access-Control-Allow-Origin:
67
+ - ! '*'
68
+ Cache-Control:
69
+ - no-store
70
+ Content-Type:
71
+ - text/javascript; charset=UTF-8
72
+ Expires:
73
+ - Sat, 01 Jan 2000 00:00:00 GMT
74
+ Pragma:
75
+ - no-cache
76
+ Www-Authenticate:
77
+ - ! 'OAuth "Facebook Platform" "invalid_token" "Error validating access token:
78
+ Session has expired at unix time 1355932800. The current unix time is 1355934833."'
79
+ X-Fb-Rev:
80
+ - '698469'
81
+ X-Fb-Debug:
82
+ - Kkjlojh5eu19FxaW5yu6N5A+5xmmbKyfKsCpa+y2eOc=
83
+ Date:
84
+ - Wed, 19 Dec 2012 16:33:53 GMT
85
+ Connection:
86
+ - keep-alive
87
+ Content-Length:
88
+ - '191'
89
+ body:
90
+ encoding: US-ASCII
91
+ string: ! '{"error":{"message":"Error validating access token: Session has expired
92
+ at unix time 1355932800. The current unix time is 1355934833.","type":"OAuthException","code":190,"error_subcode":463}}'
93
+ http_version:
94
+ recorded_at: Wed, 19 Dec 2012 16:33:53 GMT
95
+ recorded_with: VCR 2.2.4
@@ -0,0 +1,93 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=eminem,sting&type=adkeywordvalid
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - ! '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Access-Control-Allow-Origin:
22
+ - ! '*'
23
+ Cache-Control:
24
+ - private, no-cache, no-store, must-revalidate
25
+ Content-Type:
26
+ - text/javascript; charset=UTF-8
27
+ Etag:
28
+ - ! '"a684dbf074d5467a7775189984027b177954edef"'
29
+ Expires:
30
+ - Sat, 01 Jan 2000 00:00:00 GMT
31
+ Pragma:
32
+ - no-cache
33
+ X-Fb-Rev:
34
+ - '698469'
35
+ X-Fb-Debug:
36
+ - vtS1+m1EAAr/YCY4TKxUueU+DfmYhcASPsoK5LMzkW8=
37
+ Date:
38
+ - Wed, 19 Dec 2012 15:13:41 GMT
39
+ Connection:
40
+ - keep-alive
41
+ Content-Length:
42
+ - '109'
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ! '{"data":[{"name":"Eminem","valid":true,"id":6003170652434},{"name":"Sting","valid":true,"id":6003164299249}]}'
46
+ http_version:
47
+ recorded_at: Wed, 19 Dec 2012 15:13:42 GMT
48
+ - request:
49
+ method: get
50
+ uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22eminem%22,%22sting%22%5D,%22age_min%22:13,%22connections%22:%5B%5D,%22broad_age%22:false%7D
51
+ body:
52
+ encoding: US-ASCII
53
+ string: ''
54
+ headers:
55
+ Accept-Encoding:
56
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
57
+ Accept:
58
+ - ! '*/*'
59
+ User-Agent:
60
+ - Ruby
61
+ response:
62
+ status:
63
+ code: 200
64
+ message: OK
65
+ headers:
66
+ Access-Control-Allow-Origin:
67
+ - ! '*'
68
+ Cache-Control:
69
+ - private, no-cache, no-store, must-revalidate
70
+ Content-Type:
71
+ - text/javascript; charset=UTF-8
72
+ Etag:
73
+ - ! '"486581ad6483292ae854bf5e25d36d1b564b1865"'
74
+ Expires:
75
+ - Sat, 01 Jan 2000 00:00:00 GMT
76
+ Pragma:
77
+ - no-cache
78
+ X-Fb-Rev:
79
+ - '698469'
80
+ X-Fb-Debug:
81
+ - m+Eupy9dFg5wCI+Ej1LdCnZ73lJ1YHyikHIHA1+ET5Y=
82
+ Date:
83
+ - Wed, 19 Dec 2012 15:13:43 GMT
84
+ Connection:
85
+ - keep-alive
86
+ Content-Length:
87
+ - '322'
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ! '{"users":16830580,"bid_estimations":[{"location":3,"cpc_min":43,"cpc_median":71,"cpc_max":145,"cpm_min":2,"cpm_median":15,"cpm_max":502}],"imp_estimates":[],"data":{"users":16830580,"bid_estimations":[{"location":3,"cpc_min":43,"cpc_median":71,"cpc_max":145,"cpm_min":2,"cpm_median":15,"cpm_max":502}],"imp_estimates":[]}}'
91
+ http_version:
92
+ recorded_at: Wed, 19 Dec 2012 15:13:43 GMT
93
+ recorded_with: VCR 2.2.4
@@ -0,0 +1,93 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=sting&type=adkeywordvalid
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - ! '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Access-Control-Allow-Origin:
22
+ - ! '*'
23
+ Cache-Control:
24
+ - private, no-cache, no-store, must-revalidate
25
+ Content-Type:
26
+ - text/javascript; charset=UTF-8
27
+ Etag:
28
+ - ! '"66bd8a85c55324c07c1c2afcb1eac4e2fd358bf5"'
29
+ Expires:
30
+ - Sat, 01 Jan 2000 00:00:00 GMT
31
+ Pragma:
32
+ - no-cache
33
+ X-Fb-Rev:
34
+ - '698469'
35
+ X-Fb-Debug:
36
+ - XuqZnN5WjRA/b3sTn4Nz0jyvTkw2S0OCP5x8OKrUO54=
37
+ Date:
38
+ - Wed, 19 Dec 2012 15:20:53 GMT
39
+ Connection:
40
+ - keep-alive
41
+ Content-Length:
42
+ - '59'
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ! '{"data":[{"name":"Sting","valid":true,"id":6003164299249}]}'
46
+ http_version:
47
+ recorded_at: Wed, 19 Dec 2012 15:20:53 GMT
48
+ - request:
49
+ method: get
50
+ uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22sting%22%5D,%22age_min%22:13,%22age_max%22:24,%22genders%22:%5B2%5D,%22connections%22:%5B%5D,%22broad_age%22:false%7D
51
+ body:
52
+ encoding: US-ASCII
53
+ string: ''
54
+ headers:
55
+ Accept-Encoding:
56
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
57
+ Accept:
58
+ - ! '*/*'
59
+ User-Agent:
60
+ - Ruby
61
+ response:
62
+ status:
63
+ code: 200
64
+ message: OK
65
+ headers:
66
+ Access-Control-Allow-Origin:
67
+ - ! '*'
68
+ Cache-Control:
69
+ - private, no-cache, no-store, must-revalidate
70
+ Content-Type:
71
+ - text/javascript; charset=UTF-8
72
+ Etag:
73
+ - ! '"430ebe9f4489fdfc008a2c301d51e68d633c8978"'
74
+ Expires:
75
+ - Sat, 01 Jan 2000 00:00:00 GMT
76
+ Pragma:
77
+ - no-cache
78
+ X-Fb-Rev:
79
+ - '698469'
80
+ X-Fb-Debug:
81
+ - H+RabGZXmTXmsUVynJuDJRCthPTjpJLfPD7iwdJA3WA=
82
+ Date:
83
+ - Wed, 19 Dec 2012 15:20:55 GMT
84
+ Connection:
85
+ - keep-alive
86
+ Content-Length:
87
+ - '314'
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ! '{"users":39400,"bid_estimations":[{"location":3,"cpc_min":38,"cpc_median":58,"cpc_max":115,"cpm_min":1,"cpm_median":6,"cpm_max":383}],"imp_estimates":[],"data":{"users":39400,"bid_estimations":[{"location":3,"cpc_min":38,"cpc_median":58,"cpc_max":115,"cpm_min":1,"cpm_median":6,"cpm_max":383}],"imp_estimates":[]}}'
91
+ http_version:
92
+ recorded_at: Wed, 19 Dec 2012 15:20:55 GMT
93
+ recorded_with: VCR 2.2.4
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zuck::AdAccount do
4
+
5
+ let(:graph){ Koala::Facebook::API.new(:token) }
6
+ let(:acc){ Zuck::AdAccount.new(graph, name: :dance_in_style) }
7
+
8
+ it "initializes graph correctly" do
9
+ acc.graph.should == graph
10
+ end
11
+
12
+ it "initializes data correctly" do
13
+ acc[:name].should == :dance_in_style
14
+ end
15
+
16
+ it "defines getters" do
17
+ acc.name.should == :dance_in_style
18
+ end
19
+
20
+ it "defines setters" do
21
+ acc.name = :bazinga
22
+ acc.name.should == :bazinga
23
+ end
24
+
25
+
26
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zuck::AdCampaign do
4
+ end
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zuck::TargetingSpec do
4
+ let(:ad_account){ "2ijdsfoij" }
5
+ let(:graph){ mock('koala') }
6
+ let(:reach_response){
7
+ { # These can probably go since we have
8
+ "users" => 23688420, # vcr cassetes with http requests and
9
+ "bid_estimations" => [ # responses in place
10
+ {
11
+ "location" => 3,
12
+ "cpc_min" => 37,
13
+ "cpc_median" => 44,
14
+ "cpc_max" => 57,
15
+ "cpm_min" => 6,
16
+ "cpm_median" => 12,
17
+ "cpm_max" => 33
18
+ }
19
+ ],
20
+ "imp_estimates" => [
21
+ ],
22
+ "data" => {
23
+ "users" => 23688420,
24
+ "bid_estimations" => [
25
+ {
26
+ "location" => 3,
27
+ "cpc_min" => 37,
28
+ "cpc_median" => 44,
29
+ "cpc_max" => 57,
30
+ "cpm_min" => 6,
31
+ "cpm_median" => 12,
32
+ "cpm_max" => 33
33
+ }
34
+ ],
35
+ "imp_estimates" => [
36
+ ]
37
+ }
38
+ }
39
+ }
40
+
41
+
42
+ describe "validating keywords" do
43
+
44
+ let(:valid_keyword_result){ [{"name" => "foo", "valid" => true }] }
45
+ let(:invalid_keyword_result){ [{"name" => "sdjf", "valid" => false }] }
46
+
47
+ it "escapes commas" do
48
+ o = {type: 'adkeywordvalid', keyword_list: 'foo%2Cbar' }
49
+ graph.should_receive(:search).with(nil, o).and_return []
50
+ fts = Zuck::TargetingSpec.new(graph, ad_account, keywords: 'foo,bar')
51
+ fts.validate_keyword('foo,bar').should == false
52
+ end
53
+
54
+ it "acknowledges valid keywords" do
55
+ o = {type: 'adkeywordvalid', keyword_list: 'foo' }
56
+ graph.should_receive(:search).with(nil, o).and_return valid_keyword_result
57
+ fts = Zuck::TargetingSpec.new(graph, ad_account)
58
+
59
+ fts.validate_keyword('foo').should == true
60
+ end
61
+
62
+ it "refuses invalid keywords" do
63
+ o = {type: 'adkeywordvalid', keyword_list: 'sdjf' }
64
+ graph.should_receive(:search).with(nil, o).and_return invalid_keyword_result
65
+ fts = Zuck::TargetingSpec.new(graph, ad_account)
66
+
67
+ fts.validate_keyword('sdjf').should == false
68
+ end
69
+ end
70
+
71
+ describe "options given in spec" do
72
+ it "accepts male as gender" do
73
+ expect{
74
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male')
75
+ }.to_not raise_error
76
+ end
77
+
78
+ it "accepts male as gender for young people" do
79
+ expect{
80
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male', age_class: 'young')
81
+ }.to_not raise_error
82
+ end
83
+
84
+ it "accepts male as gender for old people" do
85
+ expect{
86
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male', age_class: 'old')
87
+ }.to_not raise_error
88
+ end
89
+
90
+ it "accepts without gender" do
91
+ expect{
92
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'])
93
+ }.to_not raise_error
94
+ end
95
+
96
+ it "accepts single keywrod" do
97
+ expect{
98
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keyword: 'foo')
99
+ }.to_not raise_error
100
+ end
101
+
102
+ it "does not accept invalid genders" do
103
+ expect{
104
+ Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'gemale')
105
+ }.to raise_error("Gender can only be male or female")
106
+ end
107
+
108
+ it "does not accept targetings with neither :keywords nor :connections" do
109
+ expect{
110
+ ts = Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], gender: 'female')
111
+ ts.fetch_reach
112
+ }.to raise_error("Need to set :keywords or :connections")
113
+ end
114
+ end
115
+
116
+ describe "fetching reach" do
117
+ let(:graph){ Koala::Facebook::API.new('AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD') }
118
+ let(:ad_account){ 'act_10150585630710217' }
119
+
120
+ it "bugs out when trying to use an invalid keyword" do
121
+ VCR.use_cassette('reach_for_invalid_keyword') do
122
+ spec = {countries: ['us'], keywords: ['eminem', 'invalidsssssssssssssss'] }
123
+ ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
124
+ expect{
125
+ ts.validate_keywords
126
+ }.to raise_error(Zuck::InvalidKeywordError, 'invalidsssssssssssssss')
127
+ end
128
+ end
129
+
130
+ it "works without gender or age" do
131
+ VCR.use_cassette('reach_for_valid_keywords') do
132
+ spec = {countries: ['us'], keywords: ['eminem', 'sting'] }
133
+ ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
134
+ reach = ts.fetch_reach
135
+ reach[:users].should == 16830580
136
+ end
137
+ end
138
+
139
+ it "works with gender and age" do
140
+ VCR.use_cassette('reach_for_valid_keywords_male_young') do
141
+ spec = {countries: ['us'], keywords: ['sting'], gender: :female, age_class: :young }
142
+ ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
143
+ reach = ts.fetch_reach
144
+ reach[:users].should == 39400
145
+ end
146
+ end
147
+
148
+ it "without instanciating manually" do
149
+ x = stub()
150
+ x.should_receive(:fetch_reach).and_return 9
151
+ Zuck::TargetingSpec.should_receive(:new).with(:graph, :ad_account, :options).and_return x
152
+
153
+ Zuck::TargetingSpec.fetch_reach(:graph, :ad_account, :options)
154
+ end
155
+
156
+ end
157
+
158
+ describe "Batch processing" do
159
+ let(:graph){ Koala::Facebook::API.new('AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD') }
160
+ let(:ad_account){ 'act_10150585630710217' }
161
+
162
+ it "doesn't split up small bunches" do
163
+ requests = [{some: :thing}] * 50
164
+ graph.should_receive(:batch).once.and_return([])
165
+ Zuck::TargetingSpec.batch_reaches(graph, ad_account, requests)
166
+ end
167
+
168
+ it "splits up into 50 request bunches" do
169
+ requests = [{some: :thing}] * 51
170
+ graph.should_receive(:batch).twice.and_return([])
171
+ Zuck::TargetingSpec.batch_reaches(graph, ad_account, requests)
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ class HTest
4
+ extend Zuck::FbObject::Helpers
5
+ include Zuck::FbObject::Helpers
6
+ end
7
+
8
+ describe Zuck::FbObject::Helpers do
9
+
10
+ let(:graph_mock){ mock('graph') }
11
+
12
+ context "get" do
13
+ it "forwards to koala" do
14
+ graph_mock.should_receive(:get_object).with('/foo').and_return(true)
15
+ HTest.send(:get, graph_mock, "/foo")
16
+ end
17
+
18
+ it "does not swallow exceptions" do
19
+ graph_mock.should_receive(:get_object).with('/foo').and_raise("broken")
20
+ expect{
21
+ HTest.send(:get, graph_mock, "/foo")
22
+ }.to raise_error("broken")
23
+ end
24
+ end
25
+
26
+ context "create_connection" do
27
+ it "forwards to koala" do
28
+ graph_mock.should_receive(:put_connections).with(:parent, :connection, :args, :opts).and_return(true)
29
+ HTest.send(:create_connection, graph_mock, :parent, :connection, :args, :opts)
30
+ end
31
+
32
+ it "does not swallow exceptions" do
33
+ graph_mock.should_receive(:put_connections).with(:parent, :connection, :args, :opts).and_raise("broken")
34
+ expect{
35
+ HTest.send(:create_connection, graph_mock, :parent, :connection, :args, :opts)
36
+ }.to raise_error("broken")
37
+ end
38
+ end
39
+
40
+ context "post" do
41
+ it "forwards to koala" do
42
+ graph_mock.should_receive(:graph_call).with("path", :data, "post", :opts).and_return(true)
43
+ HTest.send(:post, graph_mock, :path, :data, :opts)
44
+ end
45
+
46
+ it "does not swallow exceptions" do
47
+ graph_mock.should_receive(:graph_call).with("path", :data, "post", :opts).and_raise("broken")
48
+ expect{
49
+ HTest.send(:post, graph_mock, :path, :data, :opts)
50
+ }.to raise_error("broken")
51
+ end
52
+ end
53
+
54
+ context "delete" do
55
+ it "forwards to koala" do
56
+ graph_mock.should_receive(:delete_object).with(:id).and_return(true)
57
+ HTest.send(:delete, graph_mock, :id)
58
+ end
59
+
60
+ it "does not swallow exceptions" do
61
+ graph_mock.should_receive(:delete_object).with(:id).and_raise("broken")
62
+ expect{
63
+ HTest.send(:delete, graph_mock, :id)
64
+ }.to raise_error("broken")
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ class KMTest
4
+ extend Zuck::KoalaMethods
5
+ end
6
+
7
+ describe Zuck::KoalaMethods do
8
+ describe "assigning a graph instance" do
9
+
10
+ it "raises when not a Koala instance" do
11
+ expect{
12
+ KMTest.graph = :something_else
13
+ }.to raise_error "Symbol is not a Koala::Facebook::API"
14
+ KMTest.graph.should be_nil
15
+ end
16
+
17
+ it "raises when not a Koala instance" do
18
+ expect{
19
+ KMTest.graph = Koala::Facebook::API.new()
20
+ }.to raise_error
21
+ KMTest.graph.should be_nil
22
+ end
23
+
24
+ it "that's valid" do
25
+ KMTest.graph.should be_nil
26
+ KMTest.graph = Koala::Facebook::API.new(:some_token)
27
+ KMTest.graph.should_not be_nil
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ class HDTest
4
+ include Zuck::HashDelegator
5
+ known_keys :bar
6
+ end
7
+
8
+ describe Zuck::HashDelegator do
9
+
10
+ let(:del){ HDTest.new }
11
+
12
+ it "assigns a value" do
13
+ del[:foo] = :bar
14
+ del[:foo].should == :bar
15
+ end
16
+
17
+ it "has a shortcut getter" do
18
+ del[:foo] = :bar
19
+ del.data.should == {foo: :bar}
20
+ end
21
+
22
+ it "transforms keys to symbols" do
23
+ del['bar'] = :foo
24
+ del['bar'].should == :foo
25
+ del[:bar].should == :foo
26
+ end
27
+
28
+ it "becomes a pretty string" do
29
+ x = HDTest.new
30
+ x[:some] = "thing"
31
+ x[:bar] = 1
32
+ x.to_s.should == '#<HDTest some: "thing", bar: 1>'
33
+ end
34
+
35
+ it "allows to assign a hash" do
36
+ x = HDTest.new
37
+ x.set_data('some' => "thing", bar: 1)
38
+ x.to_s.should == '#<HDTest some: "thing", bar: 1>'
39
+ x[:some].should == "thing"
40
+ end
41
+
42
+ it "allows to assign a hash using a shortcut" do
43
+ x = HDTest.new
44
+ x.data = {'some' => "thing", bar: 1}
45
+ x.to_s.should == '#<HDTest some: "thing", bar: 1>'
46
+ x[:some].should == "thing"
47
+ end
48
+
49
+ it "has methods defined for the known keys" do
50
+ del[:bar] = :foo
51
+ del.bar.should == :foo
52
+ end
53
+
54
+ end