ruby-trello 0.4.0 → 0.4.1

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.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ruby Trello API
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/jeremytregunna/ruby-trello.png)](http://travis-ci.org/jeremytregunna/ruby-trello)
3
+ [![Build Status](https://secure.travis-ci.org/jeremytregunna/ruby-trello.png)](http://travis-ci.org/jeremytregunna/ruby-trello) [![Dependency Status](https://gemnasium.com/jeremytregunna/ruby-trello.png)](https://gemnasium.com/jeremytregunna/ruby-trello.png)
4
4
 
5
5
  This library implements the [Trello](http://www.trello.com/) [API](http://trello.com/api).
6
6
 
@@ -13,7 +13,8 @@ Seriously, [check it out](http://www.trello.com/).
13
13
  # gem install ruby-trello
14
14
  ```
15
15
 
16
- Full Disclosure: This library is not complete, but it does function enough to be useful.
16
+ Full Disclosure: This library is mostly complete, if you do find anything missing or not functioning as you expect it
17
+ to, please [let us know](https://trello.com/card/spot-a-bug-report-it/4f092b2ee23cb6fe6d1aaabd/17).
17
18
 
18
19
  ## Special thanks
19
20
 
data/lib/trello/action.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  module Trello
2
2
  # Action represents some event that occurred. For instance, when a card is created.
3
3
  class Action < BasicData
4
- register_attributes :id, :type, :data, :date, :member_creator_id
4
+ register_attributes :id, :type, :data, :date, :member_creator_id,
5
+ :readonly => [ :id, :type, :data, :date, :member_creator_id ]
5
6
  validates_presence_of :id, :type, :date, :member_creator_id
6
7
 
7
8
  class << self
@@ -19,7 +20,7 @@ module Trello
19
20
  attributes[:id] = fields['id']
20
21
  attributes[:type] = fields['type']
21
22
  attributes[:data] = fields['data']
22
- attributes[:date] = fields['date']
23
+ attributes[:date] = Time.iso8601(fields['date'])
23
24
  attributes[:member_creator_id] = fields['idMemberCreator']
24
25
  self
25
26
  end
@@ -40,8 +41,6 @@ module Trello
40
41
  end
41
42
 
42
43
  # Returns the member who created the action.
43
- def member_creator
44
- Member.find(member_creator_id)
45
- end
44
+ one :member_creator, :via => Member, :using => :member_creator_id
46
45
  end
47
46
  end
@@ -0,0 +1,11 @@
1
+ module Trello
2
+ class Association
3
+ attr_reader :owner, :target, :options, :proxy
4
+
5
+ def initialize(owner, target)
6
+ @owner = owner
7
+ @target = target
8
+ @options = {}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module Trello
4
+ class AssociationProxy
5
+ alias :proxy_extend :extend
6
+
7
+ instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
8
+
9
+ delegate :owner, :target, :to => :@association
10
+ delegate :count, :to => :@association
11
+
12
+ def initialize(association)
13
+ @association = association
14
+ Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
15
+ end
16
+
17
+ def proxy_assocation
18
+ @association
19
+ end
20
+
21
+ def method_missing(method, *args, &block)
22
+ if target.respond_to? method
23
+ target.send(method, *args, &block)
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def ===(other)
30
+ other === target
31
+ end
32
+
33
+ def to_ary
34
+ proxy_assocation.dup
35
+ end
36
+ alias_method :to_a, :to_ary
37
+
38
+ def <<(*records)
39
+ proxy_assocation.concat(records) && self
40
+ end
41
+ end
42
+ end
@@ -1,4 +1,5 @@
1
1
  require 'securerandom'
2
+ require "oauth"
2
3
 
3
4
  module Trello
4
5
  module Authorization
@@ -32,9 +33,28 @@ module Trello
32
33
 
33
34
  OAuthCredential = Struct.new "OAuthCredential", :key, :secret
34
35
 
36
+ # Handles the OAuth connectivity to Trello.
37
+ #
38
+ # For 2-legged OAuth, do the following:
39
+ #
40
+ # OAuthPolicy.consumer_credential = OAuthCredential.new "public_key", "secret"
41
+ # OAuthPolicy.token = OAuthCredential.new "token_key", nil
42
+ #
43
+ # For 3-legged OAuth, do the following:
44
+ #
45
+ # OAuthPolicy.consumer_credential = OAuthCredential.new "public_key", "secret"
46
+ # OAuthPolicy.return_url = "http://your.site.com/path/to/receive/post"
47
+ # OAuthPolicy.callback = Proc.new do |request_token|
48
+ # DB.save(request_token.key, request_token.secret)
49
+ # redirect_to request_token.authorize_url
50
+ # end
51
+ #
52
+ # Then, recreate the request token given the request token key and secret you saved earlier,
53
+ # and the consumer, and pass that RequestToken instance the #get_access_token method, and
54
+ # store that in OAuthPolicy.token as a OAuthCredential.
35
55
  class OAuthPolicy
36
56
  class << self
37
- attr_accessor :consumer_credential, :token
57
+ attr_accessor :consumer_credential, :token, :return_url, :callback
38
58
 
39
59
  def authorize(request)
40
60
  unless consumer_credential
@@ -42,26 +62,40 @@ module Trello
42
62
  fail "The consumer_credential has not been supplied."
43
63
  end
44
64
 
45
- request.headers = {"Authorization" => get_auth_header(request.uri, :get)}
46
- request
65
+ if token
66
+ request.headers = {"Authorization" => get_auth_header(request.uri, :get)}
67
+ request
68
+ else
69
+ consumer(:return_url => return_url, :callback_method => :postMessage)
70
+ request_token = consumer.get_request_token
71
+ callback.call request_token
72
+ return nil
73
+ end
47
74
  end
48
75
 
49
76
  private
50
77
 
51
- def get_auth_header(url, verb)
52
- require "oauth"
53
-
54
- self.token ||= OAuthCredential.new
78
+ def consumer_params(params = {})
79
+ {
80
+ :scheme => :header,
81
+ :scope => 'read,write,account',
82
+ :http_method => :get,
83
+ :request_token_path => "https://trello.com/1/OAuthGetRequestToken",
84
+ :authorize_path => "https://trello.com/1/OAuthAuthorizeToken",
85
+ :access_token_path => "https://trello.com/1/OAuthGetAccessToken"
86
+ }.merge!(params)
87
+ end
55
88
 
56
- consumer = OAuth::Consumer.new(
89
+ def consumer(options = {})
90
+ @consumer ||= OAuth::Consumer.new(
57
91
  consumer_credential.key,
58
92
  consumer_credential.secret,
59
- {
60
- :scheme => :header,
61
- :scope => 'read,write,account',
62
- :http_method => verb
63
- }
93
+ consumer_params(options)
64
94
  )
95
+ end
96
+
97
+ def get_auth_header(url, verb, options = {})
98
+ self.token ||= OAuththCredential.new
65
99
 
66
100
  request = Net::HTTP::Get.new Addressable::URI.parse(url).to_s
67
101
 
@@ -13,6 +13,9 @@ module Trello
13
13
  end
14
14
 
15
15
  def self.register_attributes(*names)
16
+ options = { :readonly => [] }
17
+ options.merge!(names.pop) if names.last.kind_of? Hash
18
+
16
19
  # Defines the attribute getter and setters.
17
20
  class_eval do
18
21
  define_method :attributes do
@@ -22,16 +25,43 @@ module Trello
22
25
  names.each do |key|
23
26
  define_method(:"#{key}") { @attributes[key] }
24
27
 
25
- define_method :"#{key}=" do |val|
26
- send(:"#{key}_will_change!") unless val == @attributes[key]
27
- @attributes[key] = val
28
+ unless options[:readonly].include?(key.to_sym)
29
+ define_method :"#{key}=" do |val|
30
+ send(:"#{key}_will_change!") unless val == @attributes[key]
31
+ @attributes[key] = val
32
+ end
28
33
  end
29
34
  end
35
+
30
36
  define_attribute_methods names
31
37
  end
32
38
  end
33
39
 
34
- register_attributes :id
40
+ def self.one(name, opts = {})
41
+ class_eval do
42
+ define_method(:"#{name}") do |*args|
43
+ options = opts.dup
44
+ klass = options.delete(:via) || Trello.const_get(name.to_s.camelize)
45
+ ident = options.delete(:using) || :id
46
+ klass.find(self.send(ident))
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.many(name, opts = {})
52
+ class_eval do
53
+ define_method(:"#{name}") do |*args|
54
+ options = opts.dup
55
+ resource = options.delete(:in) || self.class.to_s.split("::").last.downcase.pluralize
56
+ klass = options.delete(:via) || Trello.const_get(name.to_s.singularize.camelize)
57
+ params = options.merge(args[0] || {})
58
+ resources = Client.get("/#{resource}/#{id}/#{name}", options).json_into(klass)
59
+ MultiAssociation.new(self, resources).proxy
60
+ end
61
+ end
62
+ end
63
+
64
+ register_attributes :id, :readonly => [ :id ]
35
65
 
36
66
  def initialize(fields = {})
37
67
  update_fields(fields)
data/lib/trello/board.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  module Trello
2
-
3
2
  class Board < BasicData
4
- register_attributes :id, :name, :description, :url, :organization_id
3
+ register_attributes :id, :name, :description, :closed, :url, :organization_id, :prefs,
4
+ :readonly => [ :id, :url, :organization_id, :prefs ]
5
5
  validates_presence_of :id, :name
6
+ validates_length_of :name, :in => 1..16384
7
+ validates_length_of :description, :maximum => 16384
6
8
 
7
9
  include HasActions
8
10
 
@@ -49,49 +51,41 @@ module Trello
49
51
  attributes[:closed] = fields['closed'] if fields.has_key?('closed')
50
52
  attributes[:url] = fields['url'] if fields['url']
51
53
  attributes[:organization_id] = fields['idOrganization'] if fields['idOrganization']
52
-
54
+ attributes[:prefs] = fields['prefs'] || {}
53
55
  self
54
56
  end
55
57
 
56
58
  def closed?
57
- @attributes[:closed]
59
+ attributes[:closed]
60
+ end
61
+
62
+ def has_lists?
63
+ lists.size > 0
58
64
  end
59
65
 
60
66
  # Return all the cards on this board.
61
67
  #
62
- # The options hash may have a filter key which can have its value set as any
68
+ # This method, when called, can take a hash table with a filter key containing any
63
69
  # of the following values:
64
70
  # :filter => [ :none, :open, :closed, :all ] # default :open
65
- def cards(options = { :filter => :open })
66
- Client.get("/boards/#{id}/cards").json_into(Card)
67
- end
68
-
69
- def has_lists?
70
- lists.size > 0
71
- end
71
+ many :cards, :filter => :open
72
72
 
73
73
  # Returns all the lists on this board.
74
74
  #
75
- # The options hash may have a filter key which can have its value set as any
75
+ # This method, when called, can take a hash table with a filter key containing any
76
76
  # of the following values:
77
77
  # :filter => [ :none, :open, :closed, :all ] # default :open
78
- def lists(options = { :filter => :open })
79
- Client.get("/boards/#{id}/lists", options).json_into(List)
80
- end
78
+ many :lists, :filter => :open
81
79
 
82
80
  # Returns an array of members who are associated with this board.
83
81
  #
84
- # The options hash may have a filter key which can have its value set as any
82
+ # This method, when called, can take a hash table with a filter key containing any
85
83
  # of the following values:
86
84
  # :filter => [ :none, :normal, :owners, :all ] # default :all
87
- def members(options = { :filter => :all })
88
- Client.get("/boards/#{id}/members", options).json_into(Member)
89
- end
85
+ many :members, :filter => :all
90
86
 
91
87
  # Returns a reference to the organization this board belongs to.
92
- def organization
93
- Organization.find(organization_id)
94
- end
88
+ one :organization, :using => :organization_id
95
89
 
96
90
  # :nodoc:
97
91
  def request_prefix
data/lib/trello/card.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  module Trello
2
2
  # A Card is a container that can house checklists and comments; it resides inside a List.
3
3
  class Card < BasicData
4
- register_attributes :id, :short_id, :name, :description, :closed, :url, :board_id, :member_ids, :list_id
4
+ register_attributes :id, :short_id, :name, :description, :due, :closed, :url, :board_id, :member_ids, :list_id,
5
+ :readonly => [ :id, :short_id, :url, :board_id, :member_ids ]
5
6
  validates_presence_of :id, :name, :list_id
7
+ validates_length_of :name, :in => 1..16384
8
+ validates_length_of :description, :in => 0..16384
6
9
 
7
10
  include HasActions
8
11
 
@@ -29,6 +32,7 @@ module Trello
29
32
  attributes[:short_id] = fields['idShort']
30
33
  attributes[:name] = fields['name']
31
34
  attributes[:description] = fields['desc']
35
+ attributes[:due] = Time.iso8601(fields['due']) rescue nil
32
36
  attributes[:closed] = fields['closed']
33
37
  attributes[:url] = fields['url']
34
38
  attributes[:board_id] = fields['idBoard']
@@ -38,29 +42,24 @@ module Trello
38
42
  end
39
43
 
40
44
  # Returns a reference to the board this card is part of.
41
- def board
42
- Board.find(board_id)
43
- end
45
+ one :board, :using => :board_id
44
46
 
45
47
  # Returns a list of checklists associated with the card.
46
48
  #
47
49
  # The options hash may have a filter key which can have its value set as any
48
50
  # of the following values:
49
51
  # :filter => [ :none, :all ] # default :all
50
- def checklists(options = { :filter => :all })
51
- Client.get("/cards/#{id}/checklists", options).json_into(Checklist)
52
- end
52
+ many :checklists, :filter => :all
53
53
 
54
54
  # Returns a reference to the list this card is currently in.
55
- def list
56
- List.find(list_id)
57
- end
55
+ one :list, :using => :list_id
58
56
 
59
57
  # Returns a list of members who are assigned to this card.
60
58
  def members
61
- member_ids.map do |member_id|
59
+ members = member_ids.map do |member_id|
62
60
  Client.get("/members/#{member_id}").json_into(Member)
63
61
  end
62
+ MultiAssociation.new(self, members).proxy
64
63
  end
65
64
 
66
65
  # Saves a record.
@@ -83,14 +82,15 @@ module Trello
83
82
  @previously_changed = changes
84
83
  @changed_attributes.clear
85
84
 
86
- Client.put("/cards/#{@id}", {
85
+ Client.put("/cards/#{id}", {
87
86
  :name => name,
88
87
  :desc => description,
88
+ :due => due && due.utc.iso8601,
89
89
  :closed => closed,
90
90
  :idList => list_id,
91
91
  :idBoard => board_id,
92
92
  :idMembers => member_ids
93
- }).json_into(self)
93
+ })
94
94
  end
95
95
 
96
96
  # Is the record valid?
@@ -112,13 +112,19 @@ module Trello
112
112
 
113
113
  # Add a label
114
114
  def add_label(colour)
115
- return logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
115
+ unless %w{green yellow orange red purple blue}.include? colour
116
+ errors.add(:label, "colour '#{colour}' does not exist")
117
+ return Trello.logger.warn "The label colour '#{colour}' does not exist."
118
+ end
116
119
  Client.post("/cards/#{id}/labels", { :value => colour })
117
120
  end
118
121
 
119
122
  # Remove a label
120
123
  def remove_label(colour)
121
- return logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
124
+ unless %w{green yellow orange red purple blue}.include? colour
125
+ errors.add(:label, "colour '#{colour}' does not exist")
126
+ return Trello.logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
127
+ end
122
128
  Client.delete("/cards/#{id}/labels/#{colour}")
123
129
  end
124
130
 
@@ -1,8 +1,10 @@
1
1
  module Trello
2
2
  # A Checklist holds items which are like a "task" list. Checklists are linked to a card.
3
3
  class Checklist < BasicData
4
- register_attributes :id, :name, :description, :closed, :url, :check_items, :board_id, :list_id, :member_ids
4
+ register_attributes :id, :name, :description, :closed, :url, :check_items, :board_id, :list_id, :member_ids,
5
+ :readonly => [ :id, :description, :closed, :url, :check_items, :board_id, :list_id, :member_ids ]
5
6
  validates_presence_of :id, :board_id, :list_id
7
+ validates_length_of :name, :in => 1..16384
6
8
 
7
9
  class << self
8
10
  # Locate a specific checklist by its id.
@@ -42,13 +44,13 @@ module Trello
42
44
  return update! if id
43
45
 
44
46
  Client.post("/checklists", {
45
- :name => @name,
46
- :idBoard => @board_id
47
+ :name => name,
48
+ :idBoard => board_id
47
49
  }).json_into(self)
48
50
  end
49
51
 
50
52
  def update!
51
- Client.put("/checklists", { :name => @name }).json_into(self)
53
+ Client.put("/checklists", { :name => name }).json_into(self)
52
54
  end
53
55
 
54
56
  # Return a list of items on the checklist.
@@ -59,20 +61,17 @@ module Trello
59
61
  end
60
62
 
61
63
  # Return a reference to the board the checklist is on.
62
- def board
63
- Board.find(board_id)
64
- end
64
+ one :board, :using => :board_id
65
65
 
66
66
  # Return a reference to the list the checklist is on.
67
- def list
68
- List.find(list_id)
69
- end
67
+ one :list, :using => :list_id
70
68
 
71
69
  # Return a list of members active in this checklist.
72
70
  def members
73
- member_ids.map do |member_id|
71
+ members = member_ids.map do |member_id|
74
72
  Member.find(member_id)
75
73
  end
74
+ MultiAssociation.new(self, members).proxy
76
75
  end
77
76
 
78
77
  # Add an item to the checklist
data/lib/trello/client.rb CHANGED
@@ -30,6 +30,8 @@ module Trello
30
30
  request = Request.new name, uri, {}, body
31
31
  response = TInternet.execute AuthPolicy.authorize(request)
32
32
 
33
+ return '' unless response
34
+
33
35
  if response.code.to_i == 401 && response.body =~ /expired token/
34
36
  Trello.logger.error("[401 #{name.to_s.upcase} #{uri}]: Your access token has expired.")
35
37
  raise InvalidAccessToken, response.body
@@ -2,7 +2,8 @@ module Trello
2
2
  module HasActions
3
3
  # Returns a list of the actions associated with this object.
4
4
  def actions(options = {})
5
- Client.get("#{request_prefix}/actions", { :filter => :all }.merge(options)).json_into(Action)
5
+ actions = Client.get("#{request_prefix}/actions", { :filter => :all }.merge(options)).json_into(Action)
6
+ MultiAssociation.new(self, actions).proxy
6
7
  end
7
8
  end
8
9
  end
data/lib/trello/item.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Trello
2
2
  # An Item is a basic task that can be checked off and marked as completed.
3
3
  class Item < BasicData
4
- register_attributes :id, :name, :type
4
+ register_attributes :id, :name, :type, :readonly => [ :id, :name, :type ]
5
5
  validates_presence_of :id, :type
6
6
 
7
7
  # Updates the fields of an item.
@@ -1,7 +1,7 @@
1
1
  module Trello
2
2
  # Represents the state of an item.
3
3
  class ItemState < BasicData
4
- register_attributes :id, :state, :item_id
4
+ register_attributes :id, :state, :item_id, :readonly => [ :id, :state, :item_id ]
5
5
  validates_presence_of :id, :item_id
6
6
 
7
7
  # Update the fields of an item state.
data/lib/trello/list.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  module Trello
2
2
  # A List is a container which holds cards. Lists are items on a board.
3
3
  class List < BasicData
4
- register_attributes :id, :name, :closed, :board_id
4
+ register_attributes :id, :name, :closed, :board_id, :readonly => [ :id, :board_id ]
5
5
  validates_presence_of :id, :name, :board_id
6
+ validates_length_of :name, :in => 1..16384
6
7
 
7
8
  include HasActions
8
9
 
@@ -34,16 +35,16 @@ module Trello
34
35
  return update! if id
35
36
 
36
37
  Client.post("/lists", {
37
- :name => @name,
38
- :closed => @closed || false,
39
- :idBoard => @board_id
38
+ :name => name,
39
+ :closed => closed || false,
40
+ :idBoard => board_id
40
41
  }).json_into(self)
41
42
  end
42
43
 
43
44
  def update!
44
45
  Client.put("/lists", {
45
- :name => @name,
46
- :closed => @closed
46
+ :name => name,
47
+ :closed => closed
47
48
  }).json_into(self)
48
49
  end
49
50
 
@@ -53,18 +54,14 @@ module Trello
53
54
  end
54
55
 
55
56
  # Return the board the list is connected to.
56
- def board
57
- Board.find(board_id)
58
- end
57
+ one :board, :using => :board_id
59
58
 
60
59
  # Returns all the cards on this list.
61
60
  #
62
61
  # The options hash may have a filter key which can have its value set as any
63
62
  # of the following values:
64
63
  # :filter => [ :none, :open, :closed, :all ] # default :open
65
- def cards(options = { :filter => :open })
66
- Client.get("/lists/#{id}/cards", options).json_into(Card)
67
- end
64
+ many :cards, :filter => :open
68
65
 
69
66
  # :nodoc:
70
67
  def request_prefix
data/lib/trello/member.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  module Trello
2
2
  # A Member is a user of the Trello service.
3
3
  class Member < BasicData
4
- register_attributes :id, :username, :full_name, :avatar_id, :bio, :url
4
+ register_attributes :id, :username, :full_name, :avatar_id, :bio, :url, :readonly => [ :id, :username, :avatar_id, :url ]
5
5
  validates_presence_of :id, :username
6
+ validates_length_of :full_name, :minimum => 4
7
+ validates_length_of :bio, :maximum => 16384
6
8
 
7
9
  include HasActions
8
10
 
@@ -41,46 +43,51 @@ module Trello
41
43
 
42
44
  # Returns a list of the boards a member is a part of.
43
45
  #
44
- # The options hash may have a filter key which can have its value set as any
46
+ # This method, when called, can take a hash table with a filter key containing any
45
47
  # of the following values:
46
48
  # :filter => [ :none, :members, :organization, :public, :open, :closed, :all ] # default: :all
47
- def boards(options = { :filter => :all })
48
- Client.get("/members/#{username}/boards", options).json_into(Board)
49
- end
49
+ # i.e.,
50
+ # me.boards(:filter => :closed) # retrieves all closed boards
51
+ many :boards, :filter => :all
50
52
 
51
53
  # Returns a list of cards the member is assigned to.
52
54
  #
53
- # The options hash may have a filter key which can have its value set as any
55
+ # This method, when called, can take a hash table with a filter key containing any
54
56
  # of the following values:
55
57
  # :filter => [ :none, :open, :closed, :all ] # default :open
56
- def cards(options = { :filter => :open })
57
- Client.get("/members/#{username}/cards", options).json_into(Card)
58
- end
58
+ # i.e.,
59
+ # me.cards(:filter => :closed) # retrieves all closed cards
60
+ many :cards, :filter => :open
59
61
 
60
62
  # Returns a list of the organizations this member is a part of.
61
63
  #
62
- # The options hash may have a filter key which can have its value set as any
64
+ # This method, when called, can take a hash table with a filter key containing any
63
65
  # of the following values:
64
66
  # :filter => [ :none, :members, :public, :all ] # default: all
65
- def organizations(options = { :filter => :all })
66
- Client.get("/members/#{username}/organizations", options).json_into(Organization)
67
- end
67
+ # i.e.,
68
+ # me.organizations(:filter => :public) # retrieves all public organizations
69
+ many :organizations, :filter => :all
68
70
 
69
71
  # Returns a list of notifications for the user
70
- def notifications
71
- Client.get("/members/#{username}/notifications").json_into(Notification)
72
- end
72
+ many :notifications
73
73
 
74
74
  def save
75
75
  @previously_changed = changes
76
76
  @changed_attributes.clear
77
77
 
78
- # TODO: updating attributes.
78
+ return update! if id
79
+ end
80
+
81
+ def update!
82
+ Client.put(request_prefix, {
83
+ :displayName => full_name,
84
+ :bio => bio
85
+ }).json_into(self)
79
86
  end
80
87
 
81
88
  # :nodoc:
82
89
  def request_prefix
83
- "/members/#{username}"
90
+ "/members/#{id}"
84
91
  end
85
92
  end
86
93
  end
@@ -0,0 +1,10 @@
1
+ module Trello
2
+ class MultiAssociation < Association
3
+ delegate :count, :to => :target
4
+
5
+ def initialize(owner, target = [])
6
+ super
7
+ @proxy = AssociationProxy.new(self)
8
+ end
9
+ end
10
+ end