aweber 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Gemfile.lock +1 -3
  2. data/README.textile +67 -20
  3. data/aweber.gemspec +1 -1
  4. data/lib/aweber.rb +1 -0
  5. data/lib/aweber/base.rb +19 -3
  6. data/lib/aweber/collection.rb +33 -9
  7. data/lib/aweber/resource.rb +20 -1
  8. data/lib/aweber/resources.rb +1 -0
  9. data/lib/aweber/resources/account.rb +2 -0
  10. data/lib/aweber/resources/broadcast.rb +2 -0
  11. data/lib/aweber/resources/click.rb +2 -0
  12. data/lib/aweber/resources/followup.rb +2 -0
  13. data/lib/aweber/resources/integration.rb +2 -0
  14. data/lib/aweber/resources/link.rb +2 -0
  15. data/lib/aweber/resources/list.rb +11 -53
  16. data/lib/aweber/resources/message.rb +2 -0
  17. data/lib/aweber/resources/open.rb +2 -0
  18. data/lib/aweber/resources/subscriber.rb +21 -3
  19. data/lib/aweber/resources/tracked_event.rb +2 -0
  20. data/lib/aweber/resources/web_form.rb +2 -0
  21. data/lib/aweber/resources/web_form_split_test.rb +2 -0
  22. data/lib/aweber/resources/web_form_split_test_component.rb +2 -0
  23. data/spec/collection_spec.rb +40 -1
  24. data/spec/fixtures/subscribers.json +2 -2
  25. data/spec/resource_spec.rb +10 -9
  26. data/spec/resources/account_spec.rb +2 -0
  27. data/spec/resources/campaign_spec.rb +2 -0
  28. data/spec/resources/click_spec.rb +2 -0
  29. data/spec/resources/integration_spec.rb +2 -0
  30. data/spec/resources/link_spec.rb +2 -0
  31. data/spec/resources/list_spec.rb +7 -3
  32. data/spec/resources/message_spec.rb +2 -0
  33. data/spec/resources/open_spec.rb +2 -0
  34. data/spec/resources/subscriber_spec.rb +18 -1
  35. data/spec/resources/tracked_event_spec.rb +2 -0
  36. data/spec/resources/web_form_spec.rb +2 -0
  37. data/spec/resources/web_form_split_test_component_spec.rb +2 -0
  38. data/spec/resources/web_form_split_test_spec.rb +2 -0
  39. data/spec/spec_helper.rb +4 -1
  40. data/spec/support/fake_classes.rb +15 -0
  41. metadata +5 -5
  42. data/spec/fixtures/lists_page_2.json +0 -38
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aweber (1.1.0)
4
+ aweber (1.2.0)
5
5
  json_pure
6
6
  oauth
7
7
 
@@ -28,7 +28,5 @@ PLATFORMS
28
28
  DEPENDENCIES
29
29
  aweber!
30
30
  fakeweb
31
- json_pure
32
- oauth
33
31
  rspec (~> 2.1.0)
34
32
  yard (~> 0.6.0)
@@ -4,46 +4,93 @@ Official AWeber API gem.
4
4
 
5
5
  h2. Installation
6
6
 
7
- * @gem install aweber@
7
+ @gem install aweber@
8
8
 
9
- h2. Quick Start
9
+ h2. Getting Started
10
10
 
11
- First, go to "http://labs.aweber.com":http://labs.aweber.com and sign up for a free AWeber Labs account. This is how you register apps and get OAuth keys.
11
+ This guide assumes you have nothing previously setup to work with the AWeber API. It will walk through registering an account, creating an app and everything up to the point where you'll actually start working with data.
12
12
 
13
- bc.. # Register an app and use it's Consumer key and secret:
14
- oauth = AWeber::OAuth.new("consumer_key", "consumer_secret")
13
+ If you don't want to bother with all the account setup stuff, you can look in the "examples":http://github.com/aweber/aweber-ruby/tree/master/examples/ directory for just example code.
15
14
 
16
- # Go to the URL the following outputs.
17
- oauth.request_token.authorize_url
15
+ *Requires a normal AWeber account (not a Labs account)*
18
16
 
19
- # Authorize your account and copy the verification code.
20
- oauth.authorize_with_verifier("verification_code")
17
+ h3. 1. Register an AWeber Labs Account
21
18
 
22
- # Grab an AWeber::Base object and get movin'
23
- aweber = AWeber::Base.new(oauth)
24
- aweber.account.lists[123456].name
19
+ Head to "http://labs.aweber.com":http://labs.aweber.com and sign up for a free AWeber Labs account. This is how you register apps and get OAuth keys.
25
20
 
26
- p. Take a look at "examples":http://github.com/aweber/aweber-ruby/tree/master/examples/ for more examples.
21
+ h3. 2. Create an App
27
22
 
28
- h2. Getting Data
23
+ Once logged in, _Create a New App_. Once created, it will show you the Consumer Key and Secret for that app.
29
24
 
30
- Every piece of data from AWeber's API stems from an Account object. From there you access associated resources in the same way you would an ActiveRecord accosication:
25
+ h3. 3. Write Some Code
31
26
 
32
- bc. account.lists #=> #<AWeber::Collection(AWeber::Resource::List)>
33
- account.lists[1] #=> #<AWeber::Resource::List>
27
+ h4. The OAuth Handler
34
28
 
35
- h2. Modifying Subscribers
29
+ bc. oauth = AWeber::OAuth.new('consumer_key', 'consumer_secret')
36
30
 
37
- Currently, only certain attributes of Subscribers are writable:
31
+ h4. Authorize an Account
32
+
33
+ Open, what the following outputs, in a browser and use your AWeber account credentials. This will give your app permission to work with your account's data:
34
+
35
+ bc. oauth.request_token.verification_url
36
+
37
+ h4. Verification Code
38
+
39
+ After you do the above step, it will output a "Verification Code". Copy this and verify your @oauth@ object:
40
+
41
+ bc. oauth.authorize_with_verifier('verification_code')
42
+
43
+ h4. Grab an AWeber::Base
44
+
45
+ bc. aweber = AWeber::Base.new(oauth)
46
+
47
+ This object is how you access data from your account. @aweber.account@ is your account object which is the stem for all other resources. Take a look at the next section, "Usage", to find out how to work with different resources.
48
+
49
+ h2. Usage
50
+
51
+ h3. Resource Traversal
52
+
53
+ Getting resource data is much like traversing associations in ActiveRecord. Everything starts with the @account@ object and goes from there:
54
+
55
+ bc.. aweber.account.lists #=> #<AWeber::Collection>
56
+ aweber.account.lists[123] #=> #<AWeber::Resource::List>
57
+ aweber.account.lists[123].name #=> "WhateverList"
58
+
59
+ h3. Collections
60
+
61
+ @aweber.account.lists@ in the example above would be a Collection. Collections act like a normal Hash. Resources of a collection are accessed normally, using @[]@ with the key being the ID of the resource.
62
+
63
+ h4. find_by_*
64
+
65
+ Collections also support ActiveRecord style @find_by_*@ methods:
66
+
67
+ bc. aweber.account.lists.find_by_name("testlist")
68
+
69
+ h3. Resources
70
+
71
+ Resources are elements of a Collection. A single list resource would be retrieved with:
72
+
73
+ bc. aweber.account.lists[1234]
74
+
75
+ h2. Updating Resources
76
+
77
+ Currently, subscribers are the only resource you can update via the API. Everything else is read only for the time being.
78
+
79
+ h3. Updateable Subscribers
38
80
 
39
81
  * name
40
82
  * misc_notes
41
- * email (yes email)
83
+ * email
42
84
  * status
43
85
  * last_followup_message_number_sent
44
86
  * custom_fields (Hash of key/value pairs)
45
87
  * ad_tracking
46
88
 
89
+ h3. Moving Subscriber From List to List
90
+
91
+ bc. new_list = aweber.account.lists[1234]
92
+ subscriber.list = new_list
93
+
47
94
  h3. Example
48
95
 
49
96
  bc. subscriber = account.lists[654321].subscribers[123456]
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "aweber"
4
- s.version = "1.1.0"
4
+ s.version = "1.2.0"
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.summary = "Ruby interface to AWeber's API"
7
7
  s.description = "Ruby interface to AWeber's API"
@@ -13,6 +13,7 @@ module AWeber
13
13
  :clicks => :Click,
14
14
  :links => :Link,
15
15
  :lists => :List,
16
+ :campaigns => :Campaign,
16
17
  :messages => :Message,
17
18
  :opens => :Open,
18
19
  :subscribers => :Subscriber,
@@ -19,9 +19,21 @@ module AWeber
19
19
  oauth.delete(expand(uri))
20
20
  end
21
21
 
22
+ def post(uri, body={})
23
+ oauth.post(uri, body)
24
+ end
25
+
22
26
  def put(uri, body={})
23
27
  oauth.put(uri, body.to_json, {"Content-Type" => "application/json"})
24
28
  end
29
+
30
+ def path
31
+ ""
32
+ end
33
+
34
+ def inspect
35
+ "#<AWeber::Base />"
36
+ end
25
37
 
26
38
  private
27
39
 
@@ -34,7 +46,10 @@ module AWeber
34
46
  end
35
47
 
36
48
  def accounts
37
- @accounts ||= Collection.new(self, Resources::Account, get("/accounts"))
49
+ return @accounts if @accounts
50
+
51
+ response = get("/accounts").merge(:parent => self)
52
+ @accounts = Collection.new(self, Resources::Account, response)
38
53
  end
39
54
 
40
55
  def expand(uri)
@@ -42,8 +57,9 @@ module AWeber
42
57
  url = []
43
58
  url << AWeber.api_endpoint
44
59
  url << API_VERSION unless parsed.path.include? API_VERSION
45
- url << parsed.path
46
- File.join(*url)
60
+ url = [url.join("/"), parsed.path].join
61
+ url = [url, parsed.query].join("?") if parsed.query
62
+ url
47
63
  end
48
64
 
49
65
  def parse(response)
@@ -27,11 +27,12 @@ module AWeber
27
27
  class Collection < Resource
28
28
  include Enumerable
29
29
 
30
- attr_reader :entries
31
- attr_reader :next_collection_link
32
- attr_reader :prev_collection_link
33
- attr_reader :resource_type_link
34
- attr_reader :total_size
30
+ attr_accessor :entries
31
+ attr_reader :next_collection_link
32
+ attr_reader :prev_collection_link
33
+ attr_reader :resource_type_link
34
+ attr_reader :total_size
35
+ attr_reader :parent
35
36
 
36
37
  alias_method :size, :total_size
37
38
  alias_method :length, :total_size
@@ -45,13 +46,26 @@ module AWeber
45
46
  @client = client
46
47
  @klass = klass
47
48
  @entries = {}
48
- create_entries(data["entries"])
49
+ create_entries(data["entries"]) if data.include?("entries")
49
50
  @_entries = @entries.to_a
50
51
  end
51
52
 
53
+ def search(params={})
54
+ params = params.map { |k,v| "#{h(k)}=#{h(v)}" }.join("&")
55
+ uri = "#{path}?ws.op=find&#{params}"
56
+ response = client.get(uri).merge(:parent => parent)
57
+ response["total_size"] ||= response["entries"].size
58
+
59
+ self.class.new(client, @klass, response)
60
+ end
61
+
52
62
  def [](id)
53
63
  @entries[id] ||= fetch_entry(id)
54
64
  end
65
+
66
+ def []=(key, resource)
67
+ @entries[key] = resource
68
+ end
55
69
 
56
70
  def each
57
71
  (1..@total_size).each { |n| yield get_entry(n) }
@@ -60,11 +74,17 @@ module AWeber
60
74
  def inspect
61
75
  "#<AW::Collection(#{@klass.to_s}) size=\"#{size}\">"
62
76
  end
77
+
78
+ def path
79
+ parent and parent.path.to_s + @klass.path.to_s or @klass.path.to_s
80
+ end
63
81
 
64
82
  private
65
83
 
66
84
  def create_entries(entries)
67
- entries.each { |entry| @entries[entry["id"]] = @klass.new(client, entry) }
85
+ entries.each do |entry|
86
+ @entries[entry["id"]] = @klass.new(client, entry.merge(:parent => self))
87
+ end
68
88
  end
69
89
 
70
90
  def get_entry(n)
@@ -73,7 +93,7 @@ module AWeber
73
93
  end
74
94
 
75
95
  def fetch_entry(id)
76
- @klass.new(client, get(File.join(base_path, id.to_s)))
96
+ @klass.new(client, get(path).merge(:parent => self))
77
97
  end
78
98
 
79
99
  def fetch_next_group(amount=20)
@@ -86,7 +106,7 @@ module AWeber
86
106
  end
87
107
 
88
108
  def base_path
89
- URI.parse(@next_collection_link).path
109
+ URI.parse(@next_collection_link).path if @next_collection_link
90
110
  end
91
111
 
92
112
  def find_by(_attr, *args)
@@ -101,6 +121,10 @@ module AWeber
101
121
  end
102
122
  super
103
123
  end
124
+
125
+ def h(str)
126
+ CGI.escape(str.to_s)
127
+ end
104
128
 
105
129
  def client
106
130
  @client
@@ -16,6 +16,12 @@ module AWeber
16
16
 
17
17
  class << self
18
18
  attr_accessor :writable_attrs
19
+ attr_accessor :path
20
+
21
+ def basepath(path)
22
+ @path = path
23
+ end
24
+
19
25
  # Works the same as +alias_method+, but for attributes created via
20
26
  # +attr*+ methods.
21
27
  #
@@ -79,7 +85,8 @@ module AWeber
79
85
 
80
86
  resource_link = instance_variable_get("@#{name}_collection_link")
81
87
  klass = AWeber.get_class(name)
82
- collection = Collection.new(client, klass, client.get(resource_link))
88
+ response = client.get(resource_link).merge(:parent => self)
89
+ collection = Collection.new(client, klass, response)
83
90
  instance_variable_set("@#{name}", collection)
84
91
  end
85
92
  end
@@ -93,6 +100,10 @@ module AWeber
93
100
  alias_attribute :etag, :http_etag
94
101
  alias_attribute :link, :self_link
95
102
  alias_attribute :resource_type, :resource_type_link
103
+
104
+ def_delegators :client, :get, :post, :put
105
+
106
+ attr_reader :parent
96
107
 
97
108
  def initialize(client, data={})
98
109
  @client = client
@@ -120,6 +131,14 @@ module AWeber
120
131
  def <=>(other)
121
132
  @id <=> other.id
122
133
  end
134
+
135
+ def path
136
+ parent and "#{parent.path}/#{id}" or id.to_s
137
+ end
138
+
139
+ def inspect
140
+ %(#<AWeber::Resources::#{self.class} id="#{id}" />)
141
+ end
123
142
 
124
143
  private
125
144
 
@@ -4,6 +4,7 @@ require "aweber/resources/click"
4
4
  require "aweber/resources/followup"
5
5
  require "aweber/resources/link"
6
6
  require "aweber/resources/list"
7
+ require "aweber/resources/campaign"
7
8
  require "aweber/resources/message"
8
9
  require "aweber/resources/open"
9
10
  require "aweber/resources/subscriber"
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Account < Resource
4
+ basepath "/accounts"
5
+
4
6
  api_attr :lists_collection_link
5
7
  api_attr :integrations_collection_link
6
8
 
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Broadcast < Resource
4
+ basepath "/campaigns"
5
+
4
6
  api_attr :click_tracking_enabled
5
7
  api_attr :content_type
6
8
  api_attr :is_archived
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Click < Resource
4
+ basepath "/clicks"
5
+
4
6
  api_attr :event_time
5
7
  api_attr :is_earliest
6
8
  api_attr :subscriber_link
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Followup < Resource
4
+ basepath "/campaigns"
5
+
4
6
  api_attr :click_tracking_enabled
5
7
  api_attr :content_type
6
8
  api_attr :message_interval
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Integration < Resource
4
+ basepath "/integrations"
5
+
4
6
  api_attr :login
5
7
  api_attr :service_name
6
8
  end
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Link < Resource
4
+ basepath "/links"
5
+
4
6
  api_attr :total_clicks
5
7
  api_attr :total_unique_clicks
6
8
  api_attr :url
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class List < Resource
4
+ basepath "/lists"
5
+
4
6
  FOLLOWUP_TYPE_LINK = File.join(AWeber.api_url, "#followup_campaign")
5
7
  BROADCAST_TYPE_LINK = File.join(AWeber.api_url, "#broadcast_campaign")
6
8
 
@@ -11,76 +13,32 @@ module AWeber
11
13
  api_attr :web_forms_collection_link
12
14
  api_attr :web_form_split_tests_collection_link
13
15
 
16
+ has_many :campaigns
14
17
  has_many :subscribers
15
18
  has_many :web_forms
16
19
  has_many :web_form_split_tests
17
20
 
18
21
  def initialize(*args)
19
22
  super(*args)
20
- @campaigns = {}
21
23
  @followups = nil
22
24
  @broadcasts = nil
23
25
  end
24
26
 
25
- def campaigns
26
- return @campaigns unless @campaigns == {}
27
- create_followups
28
- create_broadcasts
29
- populate_campaigns
30
- @campaigns
31
- end
32
-
33
27
  def broadcasts
34
- campaigns if @broadcasts.nil?
28
+ return @broadcasts if @broadcasts
29
+
30
+ @broadcasts = AWeber::Collection.new(client, Campaign, :parent => self)
31
+ @broadcasts.entries = Hash[campaigns.select { |id, c| c.is_broadcast? }]
35
32
  @broadcasts
36
33
  end
37
34
 
38
35
  def followups
39
- campaigns if @followups.nil?
36
+ return @followups if @followups
37
+
38
+ @followups = AWeber::Collection.new(client, Campaign, :parent => self)
39
+ @followups.entries = Hash[campaigns.select { |id, c| c.is_followup? }]
40
40
  @followups
41
41
  end
42
-
43
- private
44
-
45
- def create_followups
46
- followups = _entries.select { |entry| is_followup? entry }
47
- @followups = Collection.new(client, Followup, {
48
- "entries" => followups,
49
- "total_size" => followups.length,
50
- "resource_type_link" => FOLLOWUP_TYPE_LINK
51
- })
52
- end
53
-
54
- def create_broadcasts
55
- broadcasts = _entries.select { |entry| is_broadcast? entry }
56
- @broadcasts = Collection.new(client, Broadcast, {
57
- "entries" => broadcasts,
58
- "total_size" => broadcasts.length,
59
- "resource_type_link" => BROADCAST_TYPE_LINK
60
- })
61
- end
62
-
63
- def populate_campaigns
64
- @followups.each { |id, followup| @campaigns[id] = followup }
65
- @broadcasts.each { |id, broadcast| @campaigns[id] = broadcast }
66
- end
67
-
68
- def is_followup?(entry)
69
- entry["resource_type_link"].split("#").last =~ /^followup/
70
- end
71
-
72
- def is_broadcast?(entry)
73
- entry["resource_type_link"].split("#").last =~ /^broadcast/
74
- end
75
-
76
- def _campaigns
77
- @_campaigns ||= client.get(@campaigns_collection_link)
78
- end
79
-
80
- def _entries
81
- _campaigns["entries"]
82
- end
83
-
84
42
  end
85
43
  end
86
44
  end
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Message < Resource
4
+ basepath "/messages"
5
+
4
6
  api_attr :event_time
5
7
  api_attr :last_opened
6
8
  api_attr :total_opens
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Open < Resource
4
+ basepath "/opens"
5
+
4
6
  api_attr :event_time
5
7
  api_attr :subscriber_link
6
8
 
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class Subscriber < Resource
4
+ basepath "/subscribers"
5
+
4
6
  api_attr :name, :writable => true
5
7
  api_attr :misc_notes, :writable => true
6
8
  api_attr :email, :writable => true
@@ -8,7 +10,7 @@ module AWeber
8
10
  api_attr :custom_fields, :writable => true
9
11
  api_attr :ad_tracking, :writable => true
10
12
  api_attr :last_followup_message_number_sent, :writable => true
11
-
13
+
12
14
  api_attr :ip_address
13
15
  api_attr :is_verified
14
16
  api_attr :last_followup_sent_at
@@ -18,11 +20,27 @@ module AWeber
18
20
  api_attr :unsubscribed_at
19
21
  api_attr :verified_at
20
22
  api_attr :last_followup_sent_link
21
-
23
+
22
24
  has_one :last_followup_sent
23
-
25
+
24
26
  alias_attribute :is_verified?, :is_verified
25
27
  alias_attribute :notes, :misc_notes
28
+
29
+ def list=(list)
30
+ client.post(self_link, {
31
+ "ws.op" => "move",
32
+ "list_link" => list.self_link
33
+ })
34
+ move_to(list)
35
+ end
36
+
37
+ private
38
+
39
+ def move_to(list)
40
+ old_list = self_link.match(%r[lists/(\d+)/])[1]
41
+ client.account.lists[old_list.to_i].subscribers[id] = nil
42
+ list.subscribers[id] = self
43
+ end
26
44
  end
27
45
  end
28
46
  end
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class TrackedEvent < Resource
4
+ basepath "/tracked_events"
5
+
4
6
  api_attr :event_time
5
7
  api_attr :type
6
8
  api_attr :subscriber_link
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class WebForm < Resource
4
+ basepath "/web_forms"
5
+
4
6
  api_attr :conversion_percentage
5
7
  api_attr :is_active
6
8
  api_attr :name
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class WebFormSplitTest < Resource
4
+ basepath "/web_form_split_tests"
5
+
4
6
  api_attr :components_collection_link
5
7
  api_attr :is_active
6
8
  api_attr :name
@@ -1,6 +1,8 @@
1
1
  module AWeber
2
2
  module Resources
3
3
  class WebFormSplitTestComponent < Resource
4
+ basepath "/components"
5
+
4
6
  api_attr :conversion_percentage
5
7
  api_attr :is_active
6
8
  api_attr :name
@@ -1,7 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe AWeber::Collection do
4
-
5
4
  before :each do
6
5
  @oauth = AWeber::OAuth.new("token", "secret")
7
6
  @aweber = AWeber::Base.new(@oauth)
@@ -37,4 +36,44 @@ describe AWeber::Collection do
37
36
  lists = @lists.find_by_resource_type_link("https://api.aweber.com/1.0/#list")
38
37
  lists.length.should == 3
39
38
  end
39
+
40
+ it "should have a path to its collection alone" do
41
+ @lists.path.should == "/lists"
42
+ end
43
+
44
+ it "should create resource with itself as a parent" do
45
+ collection = AWeber::Collection.new(@aweber, FakeParent)
46
+ @aweber.stub(:get).and_return({ :name => "Bob" })
47
+ collection[1].parent.should == collection
48
+ end
49
+
50
+ it "should pass path request through its parent" do
51
+ root = AWeber::Collection.new(@aweber, FakeParent)
52
+ leaf = AWeber::Resource.new(@aweber, :id => 1, :parent => root)
53
+ branch = AWeber::Collection.new(@aweber, FakeChild, :parent => leaf)
54
+ leafy = AWeber::Resource.new(@aweber, :id => 2, :parent => branch)
55
+ leafy.path.should == "/parents/1/children/2"
56
+ end
57
+
58
+ context "when searching" do
59
+ before do
60
+ @root = AWeber::Collection.new(@aweber, FakeParent)
61
+ @parent = AWeber::Resource.new(@aweber, :id => 1, :parent => @root)
62
+ @collection = AWeber::Collection.new(@aweber, FakeChild, :parent => @parent)
63
+ path = "/parents/1/children?ws.op=find&name=default123456"
64
+ @aweber.should_receive(:get).with(path).and_return({ "entries" => [] })
65
+ end
66
+
67
+ it "should search the API" do
68
+ @collection.search(:name => "default123456")
69
+ end
70
+
71
+ it "should return a new collection" do
72
+ @collection.search(:name => "default123456").should be_an AWeber::Collection
73
+ end
74
+
75
+ it "should return a new collection with the same parent" do
76
+ @collection.search(:name => "default123456").parent.should be @collection.parent
77
+ end
78
+ end
40
79
  end
@@ -1,5 +1,5 @@
1
1
  {
2
- "total_size": 47,
2
+ "total_size": 4,
3
3
  "start": 0,
4
4
  "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource",
5
5
  "entries": [{
@@ -13,7 +13,7 @@
13
13
  "verified_at": "2010-11-22 09:24:54",
14
14
  "last_followup_sent_at": "2010-11-23 12:31:58.159050-05:00",
15
15
  "subscription_url": "https://www.aweber.com/users/leads/add",
16
- "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/subscribers/50723026",
16
+ "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/subscribers/50723026",
17
17
  "is_verified": true,
18
18
  "resource_type_link": "https://api.aweber.com/1.0/#subscriber",
19
19
  "id": 50723026
@@ -1,14 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- class FakeResource < AWeber::Resource
4
- attr_accessor :foo
5
- api_attr :name, :writable => true
6
- alias_attribute :bar, :foo
7
- has_many :lists
8
- end
9
-
10
3
  describe AWeber::Resource do
11
-
12
4
  before :each do
13
5
  @oauth = AWeber::OAuth.new("token", "secret")
14
6
  @aweber = AWeber::Base.new(@oauth)
@@ -72,9 +64,18 @@ describe AWeber::Resource do
72
64
 
73
65
  it "should send a JSON respresentation of the object on save" do
74
66
  resource = FakeResource.new(@aweber)
75
- @oauth.should_receive(:put).with(resource.link, "{\"name\":\"Bob\"}")
67
+ @oauth.should_receive(:put).with(resource.link, "{\"name\":\"Bob\"}", anything)
76
68
  resource.name = "Bob"
77
69
  resource.save
78
70
  end
79
71
 
72
+ it "should return the id as path when no parent is supplied" do
73
+ FakeResource.new(@aweber, :id => 1).path.should == "1"
74
+ end
75
+
76
+ it "should have a parent" do
77
+ parent = AWeber::Collection.new(@aweber, FakeParent)
78
+ child = AWeber::Resource.new(@aweber, :id => 2, :parent => parent)
79
+ child.path.should == "/parents/2"
80
+ end
80
81
  end
@@ -4,6 +4,8 @@ describe AWeber::Resources::Account do
4
4
  include BaseObjects
5
5
  subject { aweber.account }
6
6
 
7
+ its(:path) { should == "/accounts/1" }
8
+
7
9
  it { should respond_to :id }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :self_link }
@@ -4,6 +4,8 @@ describe "AWeber::Resources::Campaign" do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047" }
8
+
7
9
  it { should respond_to :click_tracking_enabled }
8
10
  it { should respond_to :content_type }
9
11
  it { should respond_to :spam_assassin_score }
@@ -4,6 +4,8 @@ describe AWeber::Resources::Click do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047].links[136340].clicks[129530] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047/links/136340/clicks/129530" }
8
+
7
9
  it { should respond_to :event_time }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -4,6 +4,8 @@ describe AWeber::Resources::Integration do
4
4
  include BaseObjects
5
5
  subject { aweber.account.integrations[8076] }
6
6
 
7
+ its(:path) { should == "/accounts/1/integrations/8076" }
8
+
7
9
  it { should respond_to :http_etag }
8
10
  it { should respond_to :id }
9
11
  it { should respond_to :login }
@@ -4,6 +4,8 @@ describe AWeber::Resources::Link do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047].links[136340] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047/links/136340" }
8
+
7
9
  it { should respond_to :clicks_collection_link }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -1,9 +1,11 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- describe AWeber::Resources::Message do
3
+ describe AWeber::Resources::List do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1" }
8
+
7
9
  it { should respond_to :campaigns_collection_link }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -17,10 +19,12 @@ describe AWeber::Resources::Message do
17
19
  it { should respond_to :followups }
18
20
 
19
21
  it "should should have a collection of broadcasts" do
20
- subject.broadcasts.map { |id, b| b.self_link }.all? { |b| b =~ /b\d+$/ }.should be_true
22
+ subject.broadcasts.should be_an AWeber::Collection
23
+ subject.broadcasts[1].should be_an AWeber::Resources::Campaign
21
24
  end
22
25
 
23
26
  it "should should have a collection of followups" do
24
- subject.followups.map { |id, f| f.self_link }.all? { |f| f =~ /f\d+$/ }.should be_true
27
+ subject.followups.should be_an AWeber::Collection
28
+ subject.followups[1].should be_an AWeber::Resources::Campaign
25
29
  end
26
30
  end
@@ -4,6 +4,8 @@ describe AWeber::Resources::Message do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047].messages[11839] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047/messages/11839" }
8
+
7
9
  it { should respond_to :event_time }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -4,6 +4,8 @@ describe AWeber::Resources::Open do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047].messages[11839].opens[11721] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047/messages/11839/opens/11721" }
8
+
7
9
  it { should respond_to :event_time }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -22,7 +22,9 @@ describe AWeber::Resources::Subscriber do
22
22
  it { should respond_to :subscription_url }
23
23
  it { should respond_to :unsubscribed_at }
24
24
  it { should respond_to :verified_at }
25
-
25
+
26
+ its(:path) { should == "/accounts/1/lists/1/subscribers/50723026" }
27
+
26
28
  its(:writable_attrs) { should include :name }
27
29
  its(:writable_attrs) { should include :misc_notes }
28
30
  its(:writable_attrs) { should include :email }
@@ -30,4 +32,19 @@ describe AWeber::Resources::Subscriber do
30
32
  its(:writable_attrs) { should include :custom_fields }
31
33
  its(:writable_attrs) { should include :ad_tracking }
32
34
  its(:writable_attrs) { should include :last_followup_message_number_sent }
35
+
36
+ it "should move lists" do
37
+ list = "http://api.aweber.com/1.0/accounts/1/lists/987654"
38
+ json = { "ws.op" => "move", "list_link" => list }
39
+
40
+ aweber.account.lists[1550685].stub(:self_link).and_return(list)
41
+ oauth.should_receive(:post).with(subject.self_link, json)
42
+ subject.list = aweber.account.lists[1550685]
43
+ end
44
+
45
+ it "should update list when moving" do
46
+ new_list = aweber.account.lists[1550685]
47
+ subject.list = new_list
48
+ new_list.subscribers[subject.id].should == subject
49
+ end
33
50
  end
@@ -4,6 +4,8 @@ describe AWeber::Resources::TrackedEvent do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].campaigns[50000047].messages[11839].tracked_events[11839] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/campaigns/50000047/messages/11839/tracked_events/11839" }
8
+
7
9
  it { should respond_to :event_time }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -4,6 +4,8 @@ describe AWeber::Resources::WebForm do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].web_forms[1911952229] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/web_forms/1911952229" }
8
+
7
9
  it { should respond_to :conversion_percentage }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -4,6 +4,8 @@ describe AWeber::Resources::WebFormSplitTestComponent do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].web_form_split_tests[1242668124].components["612763163-513600765"] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/web_form_split_tests/1242668124/components/612763163-513600765" }
8
+
7
9
  it { should respond_to :conversion_percentage }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -4,6 +4,8 @@ describe AWeber::Resources::WebFormSplitTest do
4
4
  include BaseObjects
5
5
  subject { aweber.account.lists[1].web_form_split_tests[1242668124] }
6
6
 
7
+ its(:path) { should == "/accounts/1/lists/1/web_form_split_tests/1242668124" }
8
+
7
9
  it { should respond_to :components_collection_link }
8
10
  it { should respond_to :http_etag }
9
11
  it { should respond_to :id }
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
3
  require "aweber"
4
+ require "support/fake_classes"
4
5
  require "fakeweb"
5
6
  require 'rspec'
6
7
 
@@ -49,4 +50,6 @@ route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/links\?], fixture("link
49
50
  route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/links/\d+/clicks\?], fixture("clicks.json")
50
51
  route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/messages\?], fixture("messages.json")
51
52
  route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/messages/\d+/opens\?], fixture("opens.json")
52
- route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/messages/\d+/tracked_events\?], fixture("tracked_events.json")
53
+ route :get, %r[/accounts/\d+/lists/\d+/campaigns/[\d\w]+/messages/\d+/tracked_events\?], fixture("tracked_events.json")
54
+
55
+ route :post, %r[/accounts/\d+/lists/\d+/subscribers/\d+], "201 Created"
@@ -0,0 +1,15 @@
1
+ class FakeResource < AWeber::Resource
2
+ attr_accessor :foo
3
+ basepath "/fakes"
4
+ api_attr :name, :writable => true
5
+ alias_attribute :bar, :foo
6
+ has_many :lists
7
+ end
8
+
9
+ class FakeParent < AWeber::Resource
10
+ basepath "/parents"
11
+ end
12
+
13
+ class FakeChild < AWeber::Resource
14
+ basepath "/children"
15
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 1.1.0
9
+ version: 1.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - AWeber Communications, Inc.
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-13 00:00:00 -05:00
17
+ date: 2011-03-16 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -138,7 +138,6 @@ files:
138
138
  - spec/fixtures/links.json
139
139
  - spec/fixtures/list.json
140
140
  - spec/fixtures/lists.json
141
- - spec/fixtures/lists_page_2.json
142
141
  - spec/fixtures/message.json
143
142
  - spec/fixtures/messages.json
144
143
  - spec/fixtures/open.json
@@ -169,6 +168,7 @@ files:
169
168
  - spec/resources/web_form_split_test_component_spec.rb
170
169
  - spec/resources/web_form_split_test_spec.rb
171
170
  - spec/spec_helper.rb
171
+ - spec/support/fake_classes.rb
172
172
  has_rdoc: true
173
173
  homepage: http://github.com/aweber/AWeber-API-Ruby-Library
174
174
  licenses: []
@@ -216,7 +216,6 @@ test_files:
216
216
  - spec/fixtures/links.json
217
217
  - spec/fixtures/list.json
218
218
  - spec/fixtures/lists.json
219
- - spec/fixtures/lists_page_2.json
220
219
  - spec/fixtures/message.json
221
220
  - spec/fixtures/messages.json
222
221
  - spec/fixtures/open.json
@@ -247,3 +246,4 @@ test_files:
247
246
  - spec/resources/web_form_split_test_component_spec.rb
248
247
  - spec/resources/web_form_split_test_spec.rb
249
248
  - spec/spec_helper.rb
249
+ - spec/support/fake_classes.rb
@@ -1,38 +0,0 @@
1
- {
2
- "total_size": 6,
3
- "start": 4,
4
- "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource",
5
- "entries": [{
6
- "campaigns_collection_link": "/accounts/1/lists/4565456/campaigns",
7
- "name": "asdsa456464",
8
- "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/4565456/web_form_split_tests",
9
- "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/4565456/subscribers",
10
- "id": 4565456,
11
- "http_etag": "\"4ab41e60d14ea138a4522b3d2896942b7335c13c - ca5feee2b7fbb6febfca8af5541541ea960aaedb\"",
12
- "self_link": "https://api.aweber.com/1.0/accounts/1/lists/4565456",
13
- "resource_type_link": "https://api.aweber.com/1.0/#list",
14
- "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/4565456/web_forms"
15
- },
16
- {
17
- "campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/8975612/campaigns",
18
- "name": "default8975612",
19
- "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/8975612/web_form_split_tests",
20
- "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/8975612/subscribers",
21
- "id": 8975612,
22
- "http_etag": "\"685c00e3983add5e4efb5ca3bc7294e247f6e9fe - ca5feee2b7fbb6febfca8af5541541ea960aaedb\"",
23
- "self_link": "https://api.aweber.com/1.0/accounts/1/lists/8975612",
24
- "resource_type_link": "https://api.aweber.com/1.0/#list",
25
- "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/8975612/web_forms"
26
- },
27
- {
28
- "campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/12357254/campaigns",
29
- "name": "default123572549",
30
- "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/12357254/web_form_split_tests",
31
- "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/12357254/subscribers",
32
- "id": 12357254,
33
- "http_etag": "\"0aaa38a50287df08ccb74c7f13fca8679aab688a - ca5feee2b7fbb6febfca8af5541541ea960aaedb\"",
34
- "self_link": "https://api.aweber.com/1.0/accounts/1/lists/12357254",
35
- "resource_type_link": "https://api.aweber.com/1.0/#list",
36
- "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/12357254/web_forms"
37
- }]
38
- }