ruby-trello-wgibbs 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.md +37 -0
  2. data/lib/trello/action.rb +46 -0
  3. data/lib/trello/association.rb +11 -0
  4. data/lib/trello/association_proxy.rb +42 -0
  5. data/lib/trello/authorization.rb +114 -0
  6. data/lib/trello/basic_data.rb +84 -0
  7. data/lib/trello/board.rb +95 -0
  8. data/lib/trello/card.rb +162 -0
  9. data/lib/trello/checklist.rb +82 -0
  10. data/lib/trello/client.rb +49 -0
  11. data/lib/trello/has_actions.rb +9 -0
  12. data/lib/trello/item.rb +18 -0
  13. data/lib/trello/item_state.rb +23 -0
  14. data/lib/trello/label.rb +19 -0
  15. data/lib/trello/list.rb +71 -0
  16. data/lib/trello/member.rb +93 -0
  17. data/lib/trello/multi_association.rb +10 -0
  18. data/lib/trello/net.rb +37 -0
  19. data/lib/trello/notification.rb +48 -0
  20. data/lib/trello/organization.rb +47 -0
  21. data/lib/trello/string.rb +36 -0
  22. data/lib/trello/token.rb +24 -0
  23. data/lib/trello.rb +83 -0
  24. data/spec/action_spec.rb +71 -0
  25. data/spec/basic_auth_policy_spec.rb +56 -0
  26. data/spec/board_spec.rb +196 -0
  27. data/spec/card_spec.rb +213 -0
  28. data/spec/checklist_spec.rb +50 -0
  29. data/spec/client_spec.rb +131 -0
  30. data/spec/integration/how_to_authorize_spec.rb +53 -0
  31. data/spec/integration/how_to_use_boards_spec.rb +48 -0
  32. data/spec/integration/integration_test.rb +40 -0
  33. data/spec/item_spec.rb +27 -0
  34. data/spec/item_state_spec.rb +0 -0
  35. data/spec/list_spec.rb +50 -0
  36. data/spec/member_spec.rb +92 -0
  37. data/spec/notification_spec.rb +83 -0
  38. data/spec/oauth_policy_spec.rb +93 -0
  39. data/spec/organization_spec.rb +26 -0
  40. data/spec/spec_helper.rb +244 -0
  41. data/spec/string_spec.rb +50 -0
  42. data/spec/token_spec.rb +33 -0
  43. metadata +220 -0
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Ruby Trello API
2
+
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
+
5
+ This library implements the [Trello](http://www.trello.com/) [API](http://trello.com/api).
6
+
7
+ Trello is an awesome tool for organization. Not just aimed at developers, but everybody.
8
+ Seriously, [check it out](http://www.trello.com/).
9
+
10
+ ## Installation
11
+
12
+ ```
13
+ # gem install ruby-trello
14
+ ```
15
+
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).
18
+
19
+ ## Special thanks
20
+
21
+ A special thanks goes out to [Ben Biddington](https://github.com/ben-biddington) who has contributed a significant amount
22
+ of refactoring and functionality to be deserving of a beer and this special thanks.
23
+
24
+ ## Contributing
25
+
26
+ Several ways you can contribute. Documentation, code, tests, feature requests, bug reports.
27
+
28
+ We develop ruby-trello using [Trello itself](https://trello.com/board/ruby-trello/4f092b2ee23cb6fe6d1aaabd).
29
+
30
+ Pick up an editor, fix a test! (If you want to, of course.) Send a pull
31
+ request, and I'll look at it. I only ask a few things:
32
+
33
+ 1. Feature branches please!
34
+ 2. Adding or refactoring existing features, ensure there are tests.
35
+
36
+ Also, don't be afraid to send a pull request if your changes aren't done. Just
37
+ let me know.
@@ -0,0 +1,46 @@
1
+ module Trello
2
+ # Action represents some event that occurred. For instance, when a card is created.
3
+ class Action < BasicData
4
+ register_attributes :id, :type, :data, :date, :member_creator_id,
5
+ :readonly => [ :id, :type, :data, :date, :member_creator_id ]
6
+ validates_presence_of :id, :type, :date, :member_creator_id
7
+
8
+ class << self
9
+ # Locate a specific action and return a new Action object.
10
+ def find(id)
11
+ super(:actions, id)
12
+ end
13
+ end
14
+
15
+ # Update the attributes of an action
16
+ #
17
+ # Supply a hash of string keyed data retrieved from the Trello API representing
18
+ # an Action.
19
+ def update_fields(fields)
20
+ attributes[:id] = fields['id']
21
+ attributes[:type] = fields['type']
22
+ attributes[:data] = fields['data']
23
+ attributes[:date] = Time.iso8601(fields['date'])
24
+ attributes[:member_creator_id] = fields['idMemberCreator']
25
+ self
26
+ end
27
+
28
+ # Returns the board this action occurred on.
29
+ def board
30
+ Client.get("/actions/#{id}/board").json_into(Board)
31
+ end
32
+
33
+ # Returns the card the action occurred on.
34
+ def card
35
+ Client.get("/actions/#{id}/card").json_into(Card)
36
+ end
37
+
38
+ # Returns the list the action occurred on.
39
+ def list
40
+ Client.get("/actions/#{id}/list").json_into(List)
41
+ end
42
+
43
+ # Returns the member who created the action.
44
+ one :member_creator, :via => Member, :using => :member_creator_id
45
+ end
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
@@ -0,0 +1,114 @@
1
+ require 'securerandom'
2
+ require "oauth"
3
+
4
+ module Trello
5
+ module Authorization
6
+
7
+ AuthPolicy = Class.new
8
+
9
+ class BasicAuthPolicy
10
+ class << self
11
+ attr_accessor :developer_public_key, :member_token
12
+
13
+ def authorize(request)
14
+ the_uri = Addressable::URI.parse(request.uri)
15
+ existing_values = the_uri.query_values.nil? ? {} : the_uri.query_values
16
+ new_values = { :key => @developer_public_key, :token => @member_token }
17
+ the_uri.query_values = new_values.merge existing_values
18
+
19
+ Request.new request.verb, the_uri, request.headers
20
+ end
21
+ end
22
+ end
23
+
24
+ class Clock
25
+ def self.timestamp; Time.now.to_i; end
26
+ end
27
+
28
+ class Nonce
29
+ def self.next
30
+ SecureRandom.hex()
31
+ end
32
+ end
33
+
34
+ OAuthCredential = Struct.new "OAuthCredential", :key, :secret
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.
55
+ class OAuthPolicy
56
+ class << self
57
+ attr_accessor :consumer_credential, :token, :return_url, :callback
58
+
59
+ def authorize(request)
60
+ unless consumer_credential
61
+ Trello.logger.error "The consumer_credential has not been supplied."
62
+ fail "The consumer_credential has not been supplied."
63
+ end
64
+
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
74
+ end
75
+
76
+ private
77
+
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
88
+
89
+ def consumer(options = {})
90
+ @consumer ||= OAuth::Consumer.new(
91
+ consumer_credential.key,
92
+ consumer_credential.secret,
93
+ consumer_params(options)
94
+ )
95
+ end
96
+
97
+ def get_auth_header(url, verb, options = {})
98
+ self.token ||= OAuththCredential.new
99
+
100
+ request = Net::HTTP::Get.new Addressable::URI.parse(url).to_s
101
+
102
+ consumer.options[:signature_method] = 'HMAC-SHA1'
103
+ consumer.options[:nonce] = Nonce.next
104
+ consumer.options[:timestamp] = Clock.timestamp
105
+ consumer.options[:uri] = url
106
+
107
+ consumer.sign!(request, OAuth::Token.new(token.key, token.secret))
108
+
109
+ request['authorization']
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,84 @@
1
+ require 'trello/string'
2
+
3
+ module Trello
4
+ class BasicData
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Dirty
7
+ include ActiveModel::Serializers::JSON
8
+
9
+ class << self
10
+ def find(path, id)
11
+ Client.get("/#{path}/#{id}").json_into(self)
12
+ end
13
+ end
14
+
15
+ def self.register_attributes(*names)
16
+ options = { :readonly => [] }
17
+ options.merge!(names.pop) if names.last.kind_of? Hash
18
+
19
+ # Defines the attribute getter and setters.
20
+ class_eval do
21
+ define_method :attributes do
22
+ @attributes ||= names.inject({}) { |hash,k| hash.merge(k.to_sym => nil) }
23
+ end
24
+
25
+ names.each do |key|
26
+ define_method(:"#{key}") { @attributes[key] }
27
+
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
33
+ end
34
+ end
35
+
36
+ define_attribute_methods names
37
+ end
38
+ end
39
+
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 ]
65
+
66
+ def initialize(fields = {})
67
+ update_fields(fields)
68
+ end
69
+
70
+ def update_fields(fields)
71
+ raise NotImplementedError, "#{self.class} does not implement update_fields."
72
+ end
73
+
74
+ # Refresh the contents of our object.
75
+ def refresh!
76
+ self.class.find(id)
77
+ end
78
+
79
+ # Two objects are equal if their _id_ methods are equal.
80
+ def ==(other)
81
+ id == other.id
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,95 @@
1
+ module Trello
2
+ class Board < BasicData
3
+ register_attributes :id, :name, :description, :closed, :url, :organization_id, :prefs,
4
+ :readonly => [ :id, :url, :organization_id, :prefs ]
5
+ validates_presence_of :id, :name
6
+ validates_length_of :name, :in => 1..16384
7
+ validates_length_of :description, :maximum => 16384
8
+
9
+ include HasActions
10
+
11
+ class << self
12
+ # Finds a board.
13
+ def find(id)
14
+ super(:boards, id)
15
+ end
16
+
17
+ def create(fields)
18
+ new('name' => fields[:name],
19
+ 'desc' => fields[:description],
20
+ 'closed' => fields[:closed] || false).save
21
+ end
22
+ end
23
+
24
+ def save
25
+ return update! if id
26
+
27
+ fields = { :name => name }
28
+ fields.merge!(:desc => description) if description
29
+ fields.merge!(:idOrganization => organization_id) if organization_id
30
+
31
+ Client.post("/boards", fields).json_into(self)
32
+ end
33
+
34
+ def update!
35
+ fail "Cannot save new instance." unless self.id
36
+
37
+ @previously_changed = changes
38
+ @changed_attributes.clear
39
+
40
+ Client.put("/boards/#{self.id}/", {
41
+ :name => @name,
42
+ :description => @description,
43
+ :closed => @closed
44
+ }).json_into(self)
45
+ end
46
+
47
+ def update_fields(fields)
48
+ attributes[:id] = fields['id'] if fields['id']
49
+ attributes[:name] = fields['name'] if fields['name']
50
+ attributes[:description] = fields['desc'] if fields['desc']
51
+ attributes[:closed] = fields['closed'] if fields.has_key?('closed')
52
+ attributes[:url] = fields['url'] if fields['url']
53
+ attributes[:organization_id] = fields['idOrganization'] if fields['idOrganization']
54
+ attributes[:prefs] = fields['prefs'] || {}
55
+ self
56
+ end
57
+
58
+ def closed?
59
+ attributes[:closed]
60
+ end
61
+
62
+ def has_lists?
63
+ lists.size > 0
64
+ end
65
+
66
+ # Return all the cards on this board.
67
+ #
68
+ # This method, when called, can take a hash table with a filter key containing any
69
+ # of the following values:
70
+ # :filter => [ :none, :open, :closed, :all ] # default :open
71
+ many :cards, :filter => :open
72
+
73
+ # Returns all the lists on this board.
74
+ #
75
+ # This method, when called, can take a hash table with a filter key containing any
76
+ # of the following values:
77
+ # :filter => [ :none, :open, :closed, :all ] # default :open
78
+ many :lists, :filter => :open
79
+
80
+ # Returns an array of members who are associated with this board.
81
+ #
82
+ # This method, when called, can take a hash table with a filter key containing any
83
+ # of the following values:
84
+ # :filter => [ :none, :normal, :owners, :all ] # default :all
85
+ many :members, :filter => :all
86
+
87
+ # Returns a reference to the organization this board belongs to.
88
+ one :organization, :using => :organization_id
89
+
90
+ # :nodoc:
91
+ def request_prefix
92
+ "/boards/#{id}"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,162 @@
1
+ module Trello
2
+ # A Card is a container that can house checklists and comments; it resides inside a List.
3
+ class Card < BasicData
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 ]
6
+ validates_presence_of :id, :name, :list_id
7
+ validates_length_of :name, :in => 1..16384
8
+ validates_length_of :description, :in => 0..16384
9
+
10
+ include HasActions
11
+
12
+ class << self
13
+ # Find a specific card by its id.
14
+ def find(id)
15
+ super(:cards, id)
16
+ end
17
+
18
+ # Create a new card and save it on Trello.
19
+ def create(options)
20
+ new('name' => options[:name],
21
+ 'idList' => options[:list_id],
22
+ 'desc' => options[:description]).save
23
+ end
24
+ end
25
+
26
+ # Update the fields of a card.
27
+ #
28
+ # Supply a hash of string keyed data retrieved from the Trello API representing
29
+ # a card.
30
+ def update_fields(fields)
31
+ attributes[:id] = fields['id']
32
+ attributes[:short_id] = fields['idShort']
33
+ attributes[:name] = fields['name']
34
+ attributes[:description] = fields['desc']
35
+ attributes[:due] = Time.iso8601(fields['due']) rescue nil
36
+ attributes[:closed] = fields['closed']
37
+ attributes[:url] = fields['url']
38
+ attributes[:board_id] = fields['idBoard']
39
+ attributes[:member_ids] = fields['idMembers']
40
+ attributes[:list_id] = fields['idList']
41
+ self
42
+ end
43
+
44
+ # Returns a reference to the board this card is part of.
45
+ one :board, :using => :board_id
46
+
47
+ # Returns a list of checklists associated with the card.
48
+ #
49
+ # The options hash may have a filter key which can have its value set as any
50
+ # of the following values:
51
+ # :filter => [ :none, :all ] # default :all
52
+ many :checklists, :filter => :all
53
+
54
+ # Returns a reference to the list this card is currently in.
55
+ one :list, :using => :list_id
56
+
57
+ # Returns a list of members who are assigned to this card.
58
+ def members
59
+ members = member_ids.map do |member_id|
60
+ Client.get("/members/#{member_id}").json_into(Member)
61
+ end
62
+ MultiAssociation.new(self, members).proxy
63
+ end
64
+
65
+ # Saves a record.
66
+ def save
67
+ # If we have an id, just update our fields.
68
+ return update! if id
69
+
70
+ Client.post("/cards", {
71
+ :name => name,
72
+ :desc => description,
73
+ :idList => list_id
74
+ }).json_into(self)
75
+ end
76
+
77
+ # Update an existing record.
78
+ # Warning, this updates all fields using values already in memory. If
79
+ # an external resource has updated these fields, you should refresh!
80
+ # this object before making your changes, and before updating the record.
81
+ def update!
82
+ @previously_changed = changes
83
+ @changed_attributes.clear
84
+
85
+ Client.put("/cards/#{id}", {
86
+ :name => name,
87
+ :desc => description,
88
+ :due => due && due.utc.iso8601,
89
+ :closed => closed,
90
+ :idList => list_id,
91
+ :idBoard => board_id,
92
+ :idMembers => member_ids
93
+ })
94
+ end
95
+
96
+ # Is the record valid?
97
+ def valid?
98
+ name && list_id
99
+ end
100
+
101
+ # Add a comment with the supplied text.
102
+ def add_comment(text)
103
+ Client.post("/cards/#{id}/actions/comments", :text => text)
104
+ end
105
+
106
+ # Add a checklist to this card
107
+ def add_checklist(checklist)
108
+ Client.post("/cards/#{id}/checklists", {
109
+ :value => checklist.id
110
+ })
111
+ end
112
+
113
+ # Add a member to this card
114
+ def add_member(member)
115
+ Client.post("/cards/#{id}/members", {
116
+ :value => member.id
117
+ })
118
+ end
119
+
120
+ # Remove a member from this card
121
+ def remove_member(member)
122
+ Client.delete("/cards/#{id}/members/#{member.id}")
123
+ end
124
+
125
+ # Move this card to the given list
126
+ def move_to_list(list)
127
+ Client.put("/cards/#{id}/idList", {
128
+ :value => list.id
129
+ })
130
+ end
131
+
132
+ # Retrieve a list of labels
133
+ def labels
134
+ labels = Client.get("/cards/#{id}/labels").json_into(Label)
135
+ MultiAssociation.new(self, labels).proxy
136
+ end
137
+
138
+ # Add a label
139
+ def add_label(colour)
140
+ unless %w{green yellow orange red purple blue}.include? colour
141
+ errors.add(:label, "colour '#{colour}' does not exist")
142
+ return Trello.logger.warn "The label colour '#{colour}' does not exist."
143
+ end
144
+ Client.post("/cards/#{id}/labels", { :value => colour })
145
+ end
146
+
147
+ # Remove a label
148
+ def remove_label(colour)
149
+ unless %w{green yellow orange red purple blue}.include? colour
150
+ errors.add(:label, "colour '#{colour}' does not exist")
151
+ return Trello.logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
152
+ end
153
+ Client.delete("/cards/#{id}/labels/#{colour}")
154
+ end
155
+
156
+ # :nodoc:
157
+ def request_prefix
158
+ "/cards/#{id}"
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,82 @@
1
+ module Trello
2
+ # A Checklist holds items which are like a "task" list. Checklists are linked to a card.
3
+ class Checklist < BasicData
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 ]
6
+ validates_presence_of :id, :board_id, :list_id
7
+ validates_length_of :name, :in => 1..16384
8
+
9
+ class << self
10
+ # Locate a specific checklist by its id.
11
+ def find(id)
12
+ super(:checklists, id)
13
+ end
14
+
15
+ def create(options)
16
+ new('name' => options[:name],
17
+ 'idBoard' => options[:board_id]).save
18
+ end
19
+ end
20
+
21
+ # Update the fields of a checklist.
22
+ #
23
+ # Supply a hash of string keyed data retrieved from the Trello API representing
24
+ # a checklist.
25
+ def update_fields(fields)
26
+ attributes[:id] = fields['id']
27
+ attributes[:name] = fields['name']
28
+ attributes[:description] = fields['desc']
29
+ attributes[:closed] = fields['closed']
30
+ attributes[:url] = fields['url']
31
+ attributes[:check_items] = fields['checkItems']
32
+ attributes[:board_id] = fields['idBoard']
33
+ attributes[:member_ids] = fields['idMembers']
34
+ self
35
+ end
36
+
37
+ # Check if the checklist is currently active.
38
+ def closed?
39
+ closed
40
+ end
41
+
42
+ # Save a record.
43
+ def save
44
+ return update! if id
45
+
46
+ Client.post("/checklists", {
47
+ :name => name,
48
+ :idBoard => board_id
49
+ }).json_into(self)
50
+ end
51
+
52
+ def update!
53
+ Client.put("/checklists/#{id}", { :name => name }).json_into(self)
54
+ end
55
+
56
+ # Return a list of items on the checklist.
57
+ def items
58
+ check_items.map do |item_fields|
59
+ Item.new(item_fields)
60
+ end
61
+ end
62
+
63
+ # Return a reference to the board the checklist is on.
64
+ one :board, :using => :board_id
65
+
66
+ # Return a reference to the list the checklist is on.
67
+ one :list, :using => :list_id
68
+
69
+ # Return a list of members active in this checklist.
70
+ def members
71
+ members = member_ids.map do |member_id|
72
+ Member.find(member_id)
73
+ end
74
+ MultiAssociation.new(self, members).proxy
75
+ end
76
+
77
+ # Add an item to the checklist
78
+ def add_item(name)
79
+ Client.post("/checklists/#{id}/checkItems", { :name => name })
80
+ end
81
+ end
82
+ end