ruby-trello-wgibbs 0.4.3

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 (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