ruby-trello 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/trello.rb CHANGED
@@ -1,10 +1,28 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  require 'oauth'
6
2
  require 'json'
7
3
 
4
+ # Ruby wrapper around the Trello[http://trello.com] API
5
+ #
6
+ # First, set up your key information. You can get this information by {clicking here}[https://trello.com/1/appKey/generate].
7
+ #
8
+ # Trello.public_key = 'xxxxxxxxxxxxxxxxx'
9
+ # Trello.secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
10
+ #
11
+ # All the calls this library make to Trello require authentication using these keys. Be sure to protect them.
12
+ #
13
+ # So lets say you want to get information about the user *bobtester*. We can do something like this:
14
+ #
15
+ # bob = Member.find("bobtester")
16
+ # # Print out his name
17
+ # puts bob.full_name # "Bob Tester"
18
+ # # Print his bio
19
+ # puts bob.bio # A wonderfully delightful test user
20
+ # # How about a list of his boards?
21
+ # bob.boards
22
+ #
23
+ # And so much more. Consult the rest of the documentation for more information.
24
+ #
25
+ # Feel free to {peruse and participate in our Trello board}[https://trello.com/board/ruby-trello/4f092b2ee23cb6fe6d1aaabd]. It's completely open to the public.
8
26
  module Trello
9
27
  autoload :Action, 'trello/action'
10
28
  autoload :BasicData, 'trello/basic_data'
@@ -15,5 +33,12 @@ module Trello
15
33
  autoload :ItemState, 'trello/item_state'
16
34
  autoload :List, 'trello/list'
17
35
  autoload :Member, 'trello/member'
36
+ autoload :Notification, 'trello/notification'
18
37
  autoload :Organization, 'trello/organization'
19
- end
38
+
39
+ # Version of the Trello API that we use by default.
40
+ API_VERSION = 1
41
+
42
+ # Raise this when we can't find a record.
43
+ class RecordNotFound < StandardError; end
44
+ end
data/lib/trello/action.rb CHANGED
@@ -1,48 +1,48 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # Action represents some event that occurred. For instance, when a card is created.
6
3
  class Action < BasicData
4
+ attr_reader :id, :type, :data, :member_creator_id
5
+
7
6
  class << self
7
+ # Locate a specific action and return a new Action object.
8
8
  def find(id)
9
9
  super(:actions, id)
10
10
  end
11
11
  end
12
12
 
13
- # Fields
14
-
15
- def id
16
- fields['id']
17
- end
18
-
19
- def type
20
- fields['type']
21
- end
22
-
23
- def data
24
- fields['data']
13
+ # Update the attributes of an action
14
+ #
15
+ # Supply a hash of string keyed data retrieved from the Trello API representing
16
+ # an Action.
17
+ def update_fields(fields)
18
+ @id = fields['id']
19
+ @type = fields['type']
20
+ @data = fields['data']
21
+ @member_creator_id = fields['idMemberCreator']
25
22
  end
26
23
 
27
- # Links to other data structures
28
-
24
+ # Returns the board this action occurred on.
29
25
  def board
30
- response = Client.query("/1/actions/#{id}/board")
31
- Board.new(JSON.parse(response.read_body))
26
+ return @board if @board
27
+ @board = Client.get("/actions/#{id}/board").json_into(Board)
32
28
  end
33
29
 
30
+ # Returns the card the action occurred on.
34
31
  def card
35
- response = Client.query("/1/actions/#{id}/card")
36
- Card.new(JSON.parse(response.read_body))
32
+ return @card if @card
33
+ @card = Client.get("/actions/#{id}/card").json_into(Card)
37
34
  end
38
35
 
36
+ # Returns the list the action occurred on.
39
37
  def list
40
- response = Client.query("/1/actions/#{id}/list")
41
- List.new(JSON.parse(response.read_body))
38
+ return @list if @list
39
+ @list = Client.get("/actions/#{id}/list").json_into(List)
42
40
  end
43
41
 
42
+ # Returns the member who created the action.
44
43
  def member_creator
45
- Member.find(fields['idMemberCreator'])
44
+ return @member_creator if @member_creator
45
+ @member_creator = Member.find(member_creator_id)
46
46
  end
47
47
  end
48
- end
48
+ end
@@ -1,25 +1,32 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
1
+ require 'trello/string'
4
2
 
5
3
  module Trello
6
4
  class BasicData
7
- attr_reader :fields
5
+ attr_reader :id
8
6
 
9
7
  class << self
8
+ # Perform a query to retrieve some information at a specific path for a specific id.
10
9
  def find(path, id)
11
- response = Client.query("/1/#{path}/#{id}")
12
- new(JSON.parse(response.read_body))
10
+ Client.get("/#{path}/#{id}").json_into(self)
13
11
  end
14
12
  end
15
13
 
16
- # Fields
17
14
  def initialize(fields = {})
18
- @fields = fields
15
+ update_fields(fields)
19
16
  end
20
17
 
18
+ def update_fields(fields)
19
+ raise NotImplementedError, "#{self.class} does not implement update_fields."
20
+ end
21
+
22
+ # Refresh the contents of our object.
23
+ def refresh!
24
+ self.class.find(id)
25
+ end
26
+
27
+ # Two objects are equal if their _id_ methods are equal.
21
28
  def ==(other)
22
- @fields == other.fields
29
+ id == other.id
23
30
  end
24
31
  end
25
32
  end
data/lib/trello/board.rb CHANGED
@@ -1,70 +1,73 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # A board is a container which holds lists. This is where everything lives.
6
3
  class Board < BasicData
4
+ attr_reader :id, :name, :description, :closed, :url, :organization_id
5
+
7
6
  class << self
7
+ # Locate a board given a specific id.
8
8
  def find(id)
9
- response = Client.query("/1/boards/#{id}")
10
- new(JSON.parse(response.read_body))
9
+ super(:boards, id)
11
10
  end
12
11
  end
13
12
 
14
- # Fields
15
-
16
- def id
17
- fields['id']
18
- end
19
-
20
- def name
21
- fields['name']
22
- end
23
-
24
- def description
25
- fields['desc']
13
+ # Update the fields of a board.
14
+ #
15
+ # Supply a hash of string keyed data retrieved from the Trello API representing
16
+ # a board.
17
+ def update_fields(fields)
18
+ @id = fields['id']
19
+ @name = fields['name']
20
+ @description = fields['desc']
21
+ @closed = fields['closed']
22
+ @url = fields['url']
23
+ @organization_id = fields['idOrganization']
26
24
  end
27
25
 
28
- def closed
29
- fields['closed']
26
+ # Check if the board is active.
27
+ def closed?
28
+ closed
30
29
  end
31
30
 
32
- def url
33
- fields['url']
34
- end
35
-
36
- # Links to other data structures
37
-
31
+ # Return a timeline of actions related to this board.
38
32
  def actions
39
- response = Client.query("/1/boards/#{id}/actions")
40
- JSON.parse(response.read_body).map do |action_fields|
41
- Action.new(action_fields)
42
- end
33
+ return @actions if @actions
34
+ @actions = Client.get("/boards/#{id}/actions").json_into(Action)
43
35
  end
44
36
 
45
- def cards
46
- response = Client.query("/1/boards/#{id}/cards/all")
47
- JSON.parse(response.read_body).map do |card_fields|
48
- Card.new(card_fields)
49
- end
37
+ # Return all the cards on this board.
38
+ #
39
+ # The options hash may have a filter key which can have its value set as any
40
+ # of the following values:
41
+ # :filter => [ :none, :open, :closed, :all ] # default :open
42
+ def cards(options = { :filter => :open })
43
+ return @cards if @cards
44
+ @cards = Client.get("/boards/#{id}/cards").json_into(Card)
50
45
  end
51
46
 
52
- def lists
53
- response = Client.query("/1/boards/#{id}/lists/all")
54
- JSON.parse(response.read_body).map do |list_fields|
55
- List.new(list_fields)
56
- end
47
+ # Returns all the lists on this board.
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, :open, :closed, :all ] # default :open
52
+ def lists(options = { :filter => :open })
53
+ return @lists if @lists
54
+ @lists = Client.get("/boards/#{id}/lists", options).json_into(List)
57
55
  end
58
56
 
59
- def members
60
- response = Client.query("/1/boards/#{id}/members/all")
61
- JSON.parse(response.read_body).map do |member_fields|
62
- Member.new(member_fields)
63
- end
57
+ # Returns an array of members who are associated with this board.
58
+ #
59
+ # The options hash may have a filter key which can have its value set as any
60
+ # of the following values:
61
+ # :filter => [ :none, :normal, :owners, :all ] # default :all
62
+ def members(options = { :filter => :all })
63
+ return @members if @members
64
+ @members = Client.get("/boards/#{id}/members").json_into(Member)
64
65
  end
65
66
 
67
+ # Returns a reference to the organization this board belongs to.
66
68
  def organization
67
- Organization.find(fields['idOrganization'])
69
+ return @organization if @organization
70
+ @organization = Organization.find(organization_id)
68
71
  end
69
72
  end
70
- end
73
+ end
data/lib/trello/card.rb CHANGED
@@ -1,71 +1,99 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # A Card is a container that can house checklists and comments; it resides inside a List.
6
3
  class Card < BasicData
4
+ attr_reader :id
5
+ attr_accessor :name, :description, :closed, :url, :board_id, :member_ids, :list_id
6
+
7
7
  class << self
8
+ # Find a specific card by its id.
8
9
  def find(id)
9
10
  super(:cards, id)
10
11
  end
11
- end
12
12
 
13
- # Fields
14
-
15
- def id
16
- fields['id']
13
+ # Create a new card and save it on Trello.
14
+ def create(options)
15
+ new('name' => options[:name],
16
+ 'idList' => options[:list_id],
17
+ 'desc' => options[:description]).save!
18
+ end
17
19
  end
18
20
 
19
- def name
20
- fields['name']
21
+ # Update the fields of a card.
22
+ #
23
+ # Supply a hash of string keyed data retrieved from the Trello API representing
24
+ # a card.
25
+ def update_fields(fields)
26
+ @id = fields['id']
27
+ @name = fields['name']
28
+ @description = fields['desc']
29
+ @closed = fields['closed']
30
+ @url = fields['url']
31
+ @board_id = fields['idBoard']
32
+ @member_ids = fields['idMembers']
33
+ @list_id = fields['idList']
21
34
  end
22
35
 
23
- def description
24
- fields['desc']
36
+ # Returns a list of the actions associated with this card.
37
+ def actions
38
+ return @actions if @actions
39
+ @actions = Client.get("/cards/#{id}/actions").json_into(Action)
25
40
  end
26
41
 
27
- def closed
28
- fields['closed']
42
+ # Returns a reference to the board this card is part of.
43
+ def board
44
+ return @board if @board
45
+ @board = Board.find(board_id)
29
46
  end
30
47
 
31
- def url
32
- fields['url']
48
+ # Returns a list of checklists associated with the card.
49
+ #
50
+ # The options hash may have a filter key which can have its value set as any
51
+ # of the following values:
52
+ # :filter => [ :none, :all ] # default :all
53
+ def checklists(options = { :filter => :all })
54
+ return @checklists if @checklists
55
+ @checklists = Client.get("/cards/#{id}/checklists", options).json_into(Checklist)
33
56
  end
34
57
 
35
- # Links to other data structures
58
+ # Returns a reference to the list this card is currently in.
59
+ def list
60
+ return @list if @list
61
+ @list = List.find(list_id)
62
+ end
36
63
 
37
- def actions
38
- response = Client.query("/1/cards/#{id}/actions")
39
- JSON.parse(response.read_body).map do |action_fields|
40
- Action.new(action_fields)
64
+ # Returns a list of members who are assigned to this card.
65
+ def members
66
+ return @members if @members
67
+ @members = member_ids.map do |member_id|
68
+ Client.get("/members/#{member_id}").json_into(Member)
41
69
  end
42
70
  end
43
71
 
44
- def board
45
- Board.find(fields['idBoard'])
46
- end
72
+ # Saves a record.
73
+ def save!
74
+ return update! if id
47
75
 
48
- def checklists
49
- response = Client.query("/1/cards/#{id}/checklists")
50
- JSON.parse(response.read_body).map do |checklist_fields|
51
- Checklist.new(checklist_fields)
52
- end
76
+ Client.post("/cards", {
77
+ :name => @name,
78
+ :desc => @description,
79
+ :idList => @list_id
80
+ })
53
81
  end
54
82
 
55
- def list
56
- List.find(fields['idList'])
83
+ # Update an existing record.
84
+ def update!
85
+ # Trello doesn't support this yet. But Daniel is working on it as I
86
+ # place this comment here!
57
87
  end
58
88
 
59
- def members
60
- fields['idMembers'].map do |member_id|
61
- response = Client.query("/1/members/#{member_id}")
62
- Member.new(JSON.parse(response.read_body))
63
- end
89
+ # Is the record valid?
90
+ def valid?
91
+ @name && @list_id
64
92
  end
65
93
 
66
- # Add a comment
67
- def comment(text)
68
- response = Client.query("/1/cards/#{id}/actions/comments", :method => :put, :params => { :text => text })
94
+ # Add a comment with the supplied text.
95
+ def add_comment(text)
96
+ Client.put("/cards/#{id}/actions/comments", :text => text)
69
97
  end
70
98
  end
71
- end
99
+ end
@@ -1,57 +1,63 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # A Checklist holds items which are like a "todo" list. Checklists are linked to a card.
6
3
  class Checklist < BasicData
4
+ attr_reader :id, :name, :description, :closed, :url, :check_items, :board_id, :list_id, :member_ids
5
+
7
6
  class << self
7
+ # Locate a specific checklist by its id.
8
8
  def find(id)
9
9
  super(:checklists, id)
10
10
  end
11
11
  end
12
12
 
13
- # Fields
14
-
15
- def id
16
- fields['id']
17
- end
18
-
19
- def name
20
- fields['name']
21
- end
22
-
23
- def description
24
- fields['desc']
13
+ # Update the fields of a checklist.
14
+ #
15
+ # Supply a hash of string keyed data retrieved from the Trello API representing
16
+ # a checklist.
17
+ def update_fields(fields)
18
+ @id = fields['id']
19
+ @name = fields['name']
20
+ @description = fields['desc']
21
+ @closed = fields['closed']
22
+ @url = fields['url']
23
+ @check_items = fields['checkItems']
24
+ @board_id = fields['idBoard']
25
+ @member_ids = fields['idMembers']
25
26
  end
26
27
 
28
+ # Check if the checklist is currently active.
27
29
  def closed?
28
- fields['closed']
29
- end
30
-
31
- def url
32
- fields['url']
30
+ closed
33
31
  end
34
32
 
35
- # Links to other data structures
36
-
33
+ # Return a list of items on the checklist.
37
34
  def items
38
- fields['checkItems'].map do |item_fields|
35
+ return @items if @items
36
+
37
+ @items = check_items.map do |item_fields|
39
38
  Item.new(item_fields)
40
39
  end
41
40
  end
42
41
 
42
+ # Return a reference to the board the checklist is on.
43
43
  def board
44
- Board.find(fields['idBoard'])
44
+ return @board if @board
45
+ @board = Board.find(board_id)
45
46
  end
46
47
 
48
+ # Return a reference to the list the checklist is on.
47
49
  def list
48
- List.find(fields['idList'])
50
+ return @list if @list
51
+ @list = List.find(list_id)
49
52
  end
50
53
 
54
+ # Return a list of members active in this checklist.
51
55
  def members
52
- fields['idMembers'].map do |member_id|
56
+ return @members if @members
57
+
58
+ @members = member_ids.map do |member_id|
53
59
  Member.find(member_id)
54
60
  end
55
61
  end
56
62
  end
57
- end
63
+ end
data/lib/trello/client.rb CHANGED
@@ -1,22 +1,47 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  require 'addressable/uri'
6
2
 
7
3
  module Trello
4
+ # Client is used to handle the OAuth connection to Trello as well as send requests over that authenticated socket.
8
5
  class Client
9
6
  class EnterYourPublicKey < StandardError; end
10
7
  class EnterYourSecret < StandardError; end
11
8
 
12
9
  class << self
13
- attr_writer :public_key, :secret, :app_name
10
+ attr_writer :public_key, :secret
14
11
 
15
- def query(path, options = { :method => :get, :params => {} })
16
- uri = Addressable::URI.parse("https://api.trello.com#{path}")
12
+ # call-seq:
13
+ # get(path, params)
14
+ # post(path, params)
15
+ # put(path, params)
16
+ # delete(path, params)
17
+ # query(api_version, path, options)
18
+ #
19
+ # Makes a query to a specific path via one of the four HTTP methods, optionally
20
+ # with a hash specifying parameters to pass to Trello.
21
+ #
22
+ # You should use one of _.get_, _.post_, _.put_ or _.delete_ instead of this method.
23
+ def query(api_version, path, options = { :method => :get, :params => {} })
24
+ uri = Addressable::URI.parse("https://api.trello.com/#{api_version}#{path}")
17
25
  uri.query_values = options[:params]
18
26
 
19
27
  access_token.send(options[:method], uri.to_s)
28
+ rescue OAuth::Problem => e
29
+ headers = []
30
+ e.request.each_header do |k,v|
31
+ headers << [k, v]
32
+ end
33
+
34
+ logger.error("[#{@access_token}] Disposing of access token.\n#{e.inspect}")
35
+ logger.info("[#{@access_token}] Headers: #{headers.inspect}\nRequest Body: #{e.request.body}")
36
+ @access_token = nil
37
+ end
38
+
39
+ %w{get post put delete}.each do |http_method|
40
+ send(:define_method, http_method) do |*args|
41
+ path = args[0]
42
+ params = args[1] || {}
43
+ query(API_VERSION, path, :method => http_method, :params => params).read_body
44
+ end
20
45
  end
21
46
 
22
47
  protected
@@ -39,4 +64,4 @@ module Trello
39
64
  end
40
65
  end
41
66
  end
42
- end
67
+ end
data/lib/trello/item.rb CHANGED
@@ -1,27 +1,16 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # An Item is a basic task that can be checked off and marked as completed.
6
3
  class Item < BasicData
7
- class << self
8
- def find(nothing)
9
- raise 'This operation does not make sense'
10
- end
11
- end
12
-
13
- # Fields
14
-
15
- def id
16
- fields['id']
17
- end
18
-
19
- def name
20
- fields['name']
21
- end
4
+ attr_reader :id, :name, :type
22
5
 
23
- def type
24
- fields['type']
6
+ # Updates the fields of an item.
7
+ #
8
+ # Supply a hash of string keyed data retrieved from the Trello API representing
9
+ # an item.
10
+ def update_fields(fields)
11
+ @id = fields['id']
12
+ @name = fields['name']
13
+ @type = fields['type']
25
14
  end
26
15
  end
27
16
  end
@@ -1,38 +1,21 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # Represents the state of an item.
6
3
  class ItemState < BasicData
7
- class << self
8
- def find(nothing)
9
- raise 'This operation does not make sense'
10
- end
11
- end
12
-
13
- # Fields
14
-
15
- def id
16
- fields['id']
17
- end
18
-
19
- def state
20
- fields['state']
21
- end
4
+ attr_reader :id, :state, :item_id
22
5
 
23
- # Until #item is implemented, this will do
24
- def item_id
25
- fields['idItem']
6
+ # Update the fields of an item state.
7
+ #
8
+ # Supply a hash of string keyed data retrieved from the Trello API representing
9
+ # an item state.
10
+ def update_fields(fields)
11
+ @id = fields['id']
12
+ @state = fields['state']
13
+ @item_id = fields['idItem']
26
14
  end
27
15
 
28
- # Links to other data structures
29
-
16
+ # Return the item this state belongs to.
30
17
  def item
31
- # Nothing here for now. I will implement it myself later, but Trello really
32
- # needs an API to query check items in my estimation. Otherwise, the "idCheckItem"
33
- # key serves no good purpose. I'd have to know what checklist this state belongs
34
- # to, and then query all of its items, comparing the ID as I go. O(n) at the best
35
- # of times. If I don't have the checklist, then we're O(m*n^2). Horrible.
18
+ Item.find(@item_id)
36
19
  end
37
20
  end
38
21
  end
data/lib/trello/list.rb CHANGED
@@ -1,46 +1,51 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # A List is a container which holds cards. Lists are items on a board.
6
3
  class List < BasicData
4
+ attr_reader :id, :name, :closed, :board_id
5
+
7
6
  class << self
7
+ # Finds a specific list, given an id.
8
8
  def find(id)
9
9
  super(:lists, id)
10
10
  end
11
11
  end
12
12
 
13
- # Fields
14
-
15
- def id
16
- fields['id']
17
- end
18
-
19
- def name
20
- fields['name']
13
+ # Updates the fields of a list.
14
+ #
15
+ # Supply a hash of string keyed data retrieved from the Trello API representing
16
+ # a List.
17
+ def update_fields(fields)
18
+ @id = fields['id']
19
+ @name = fields['name']
20
+ @closed = fields['closed']
21
+ @board_id = fields['idBoard']
21
22
  end
22
23
 
23
- def closed
24
- fields['closed']
24
+ # Check if the list is not active anymore.
25
+ def closed?
26
+ closed
25
27
  end
26
28
 
27
- # Links to other data structures
28
-
29
+ # Return a timeline of events related to this list.
29
30
  def actions
30
- response = Client.query("/1/lists/#{id}/actions")
31
- JSON.parse(response.read_body).map do |action_fields|
32
- Action.new(action_fields)
33
- end
31
+ return @actions if @actions
32
+ @actions = Client.get("/lists/#{id}/actions").json_into(Action)
34
33
  end
35
34
 
35
+ # Return the board the list is connected to.
36
36
  def board
37
- Board.find(fields['idBoard'])
37
+ return @board if @board
38
+ @board = Board.find(board_id)
38
39
  end
39
40
 
40
- def cards
41
- fields['cards'].map do |c|
42
- Card.new(c)
43
- end
41
+ # Returns all the cards on this list.
42
+ #
43
+ # The options hash may have a filter key which can have its value set as any
44
+ # of the following values:
45
+ # :filter => [ :none, :open, :closed, :all ] # default :open
46
+ def cards(options = { :filter => :open })
47
+ return @cards if @cards
48
+ @cards = Client.get("/lists/#{id}/cards", options).json_into(Card)
44
49
  end
45
50
  end
46
- end
51
+ end
data/lib/trello/member.rb CHANGED
@@ -1,73 +1,82 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # A Member is a user of the Trello service.
6
3
  class Member < BasicData
4
+ attr_reader :id
5
+ attr_accessor :full_name, :username, :gravatar_id, :bio, :url
6
+
7
7
  class << self
8
+ # Finds a user
9
+ #
10
+ # The argument may be specified as either an _id_ or a _username_.
8
11
  def find(id_or_username)
9
12
  super(:members, id_or_username)
10
13
  end
11
14
  end
12
15
 
13
- def initialize(fields = {})
14
- @fields = fields
15
- end
16
-
17
- # Fields of a user
18
-
19
- def id
20
- @fields['id']
21
- end
22
-
23
- def full_name
24
- @fields['fullName']
25
- end
26
-
27
- def username
28
- @fields['username']
16
+ # Update the fields of a member.
17
+ #
18
+ # Supply a hash of string keyed data retrieved from the Trello API representing
19
+ # an Member.
20
+ def update_fields(fields)
21
+ @id = fields['id']
22
+ @full_name = fields['fullName']
23
+ @username = fields['username']
24
+ @gravatar_id = fields['gravatar']
25
+ @bio = fields['bio']
26
+ @url = fields['url']
29
27
  end
30
28
 
31
- def gravatar_id
32
- @fields['gravatar']
29
+ # Returns a list of the users actions.
30
+ def actions
31
+ return @actions if @actions
32
+ @actions = Client.get("/members/#{username}/actions").json_into(Action)
33
33
  end
34
34
 
35
- def bio
36
- @fields['bio']
35
+ # Returns a list of the boards a member is a part of.
36
+ #
37
+ # The options hash may have a filter key which can have its value set as any
38
+ # of the following values:
39
+ # :filter => [ :none, :members, :organization, :public, :open, :closed, :all ] # default: :all
40
+ def boards(options = { :filter => :all })
41
+ return @boards if @boards
42
+ @boards = Client.get("/members/#{username}/boards", options).json_into(Board)
37
43
  end
38
44
 
39
- def url
40
- @fields['url']
45
+ # Returns a list of cards the member is assigned to.
46
+ #
47
+ # The options hash may have a filter key which can have its value set as any
48
+ # of the following values:
49
+ # :filter => [ :none, :open, :closed, :all ] # default :open
50
+ def cards(options = { :filter => :open })
51
+ return @cards if @cards
52
+ @cards = Client.get("/members/#{username}/cards", options).json_into(Card)
41
53
  end
42
54
 
43
- # Links to other data structures
44
-
45
- def actions
46
- response = Client.query("/1/members/#{username}/actions")
47
- JSON.parse(response.read_body).map do |action_fields|
48
- Action.new(action_fields)
49
- end
55
+ # Returns a list of the organizations this member is a part of.
56
+ #
57
+ # The options hash may have a filter key which can have its value set as any
58
+ # of the following values:
59
+ # :filter => [ :none, :members, :public, :all ] # default: all
60
+ def organizations(options = { :filter => :all })
61
+ return @organizations if @organizations
62
+ @organizations = Client.get("/members/#{username}/organizations", options).json_into(Organization)
50
63
  end
51
64
 
52
- def boards
53
- response = Client.query("/1/members/#{username}/boards/all")
54
- JSON.parse(response.read_body).map do |board_fields|
55
- Board.new(board_fields)
56
- end
65
+ # Returns a list of notifications for the user
66
+ def notifications
67
+ Client.get("/members/#{username}/notifications").json_into(Notification)
57
68
  end
58
69
 
59
- def cards
60
- response = Client.query("/1/members/#{username}/cards/all")
61
- JSON.parse(response.read_body).map do |card_fields|
62
- Card.new(card_fields)
63
- end
64
- end
65
-
66
- def organizations
67
- response = Client.query("/1/members/#{username}/organizations/all")
68
- JSON.parse(response.read_body).map do |org_fields|
69
- Organization.new(org_fields)
70
- end
70
+ # Returns a hash of the items that would be returned by Trello.
71
+ def to_hash
72
+ {
73
+ 'id' => id,
74
+ 'fullName' => full_name,
75
+ 'username' => username,
76
+ 'gravatar' => gravatar_id,
77
+ 'bio' => bio,
78
+ 'url' => url
79
+ }
71
80
  end
72
81
  end
73
- end
82
+ end
@@ -0,0 +1,10 @@
1
+ module Trello
2
+ # Notifications for members
3
+ #
4
+ # This class is not yet implemented as the feature set is not known yet.
5
+ class Notification < BasicData
6
+ def update_fields(fields)
7
+ @id = fields['id']
8
+ end
9
+ end
10
+ end
@@ -1,62 +1,43 @@
1
- # Ruby wrapper around the Trello API
2
- # Copyright (c) 2012, Jeremy Tregunna
3
- # Use and distribution terms may be found in the file LICENSE included in this distribution.
4
-
5
1
  module Trello
2
+ # Organizations are useful for linking members together.
6
3
  class Organization < BasicData
4
+ attr_reader :id, :name, :display_name, :description, :url
5
+
7
6
  class << self
7
+ # Find an organization by its id.
8
8
  def find(id)
9
9
  super(:organizations, id)
10
10
  end
11
11
  end
12
12
 
13
- def initialize(fields = {})
14
- @fields = fields
15
- end
16
-
17
- # Fields
18
-
19
- def id
20
- @fields['id']
21
- end
22
-
23
- def name
24
- @fields['name']
25
- end
26
-
27
- def display_name
28
- @fields['display_name']
13
+ # Update the fields of an organization.
14
+ #
15
+ # Supply a hash of string keyed data retrieved from the Trello API representing
16
+ # an Organization.
17
+ def update_fields(fields)
18
+ @id = fields['id']
19
+ @name = fields['name']
20
+ @display_name = fields['displayName']
21
+ @description = fields['description']
22
+ @url = fields['url']
29
23
  end
30
24
 
31
- def description
32
- @fields['desc']
33
- end
34
-
35
- def url
36
- @fields['url']
37
- end
38
-
39
- # Links to other data structures
40
-
25
+ # Returns a timeline of actions.
41
26
  def actions
42
- response = Client.query("/1/organizations/#{id}/actions")
43
- JSON.parse(response.read_body).map do |action_fields|
44
- Action.new(action_fields)
45
- end
27
+ return @actions if @actions
28
+ @actions = Client.get("/organizations/#{id}/actions").json_into(Action)
46
29
  end
47
30
 
31
+ # Returns a list of boards under this organization.
48
32
  def boards
49
- response = Client.query("/1/organizations/#{id}/boards/all")
50
- JSON.parse(response.read_body).map do |board_fields|
51
- Board.new(board_fields)
52
- end
33
+ return @boards if @boards
34
+ @boards = Client.get("/organizations/#{id}/boards/all").json_into(Board)
53
35
  end
54
36
 
37
+ # Returns an array of members associated with the organization.
55
38
  def members
56
- response = Client.query("/1/organizations/#{id}/members/all")
57
- JSON.parse(response.read_body).map do |member_fields|
58
- Member.new(member_fields)
59
- end
39
+ return @members if @members
40
+ @members = Client.get("/organizations/#{id}/members/all").json_into(Member)
60
41
  end
61
42
  end
62
- end
43
+ end
@@ -0,0 +1,33 @@
1
+ class String
2
+ # Decodes some JSON text in the receiver, and marshals it into a class specified
3
+ # in _obj_. If _obj_ is not a class, then we marshall the data into that instance
4
+ # via _update_fields_.
5
+ #
6
+ # For instance:
7
+ #
8
+ # class Stuff
9
+ # attr_reader :a, :b
10
+ # def initialize(values)
11
+ # @a = values['a']
12
+ # @b = values['b']
13
+ # end
14
+ # end
15
+ # thing = '{"a":42,"b":"foo"}'.json_into(Stuff)
16
+ # thing.a == 42
17
+ # thing.b == "foo"
18
+ def json_into(obj)
19
+ data = JSON.parse(self)
20
+ action = obj.kind_of?(Class) ? :new : :update_fields
21
+ if data.kind_of? Hash
22
+ obj.send(action, JSON.parse(self))
23
+ else
24
+ data.map { |element| obj.send(action, element) }
25
+ end
26
+ rescue JSON::ParserError => json_error
27
+ if json_error.message =~ /model not found/
28
+ raise Trello::RecordNotFound
29
+ else
30
+ raise
31
+ end
32
+ end
33
+ end
data/spec/board_spec.rb CHANGED
@@ -41,7 +41,7 @@ module Trello
41
41
 
42
42
  context "cards" do
43
43
  it "gets its list of cards" do
44
- stub_request(:get, "https://api.trello.com/1/boards/abcdef123456789123456789/cards/all?").
44
+ stub_request(:get, "https://api.trello.com/1/boards/abcdef123456789123456789/cards?").
45
45
  with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
46
46
  to_return(:status => 200, :headers => {}, :body => cards_payload)
47
47
 
data/spec/card_spec.rb CHANGED
@@ -17,6 +17,33 @@ module Trello
17
17
  @card = Card.find('abcdef123456789123456789')
18
18
  end
19
19
 
20
+ context "creating" do
21
+ it "creates a new record" do
22
+ card = Card.new(cards_details.first)
23
+ card.should be_valid
24
+ end
25
+
26
+ it 'must not be valid if not given a name' do
27
+ card = Card.new('idList' => lists_details.first['id'])
28
+ card.should_not be_valid
29
+ end
30
+
31
+ it 'must not be valid if not given a list id' do
32
+ card = Card.new('name' => lists_details.first['name'])
33
+ card.should_not be_valid
34
+ end
35
+
36
+ it 'creates a new record and saves it on Trello' do
37
+ payload = {
38
+ :name => 'Test Card',
39
+ :desc => '',
40
+ }
41
+ stub_trello_request!(:post, '/cards', payload.merge(:idList => lists_details.first['id']))
42
+ card = Card.create(payload.merge(:list_id => lists_details.first['id']))
43
+ card.should == ''
44
+ end
45
+ end
46
+
20
47
  context "fields" do
21
48
  it "gets its id" do
22
49
  @card.id.should_not be_nil
data/spec/list_spec.rb CHANGED
@@ -10,14 +10,10 @@ module Trello
10
10
  end
11
11
 
12
12
  before(:each) do
13
- stub_request(:get, "https://api.trello.com/1/lists/abcdef123456789123456789?").
14
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
15
- to_return(:status => 200, :headers => {}, :body => JSON.generate(lists_details.first))
16
- stub_request(:get, "https://api.trello.com/1/boards/abcdef123456789123456789?").
17
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
18
- to_return(:status => 200, :headers => {}, :body => JSON.generate(boards_details.first))
19
-
20
- @list = List.find("abcdef123456789123456789")
13
+ stub_trello_request!(:get, "/lists/abcdef123456789123456789?", nil, JSON.generate(lists_details.first))
14
+ stub_trello_request!(:get, "/boards/abcdef123456789123456789?", nil, JSON.generate(boards_details.first))
15
+
16
+ @list = List.find("abcdef123456789123456789")
21
17
  end
22
18
 
23
19
  context "fields" do
@@ -40,6 +36,7 @@ module Trello
40
36
 
41
37
  context "cards" do
42
38
  it "has a list of cards" do
39
+ stub_trello_request!(:get, "/lists/abcdef123456789123456789/cards?", { :filter => :open }, cards_payload)
43
40
  @list.cards.count.should be > 0
44
41
  end
45
42
  end
data/spec/member_spec.rb CHANGED
@@ -12,29 +12,21 @@ module Trello
12
12
  end
13
13
 
14
14
  before(:each) do
15
- stub_request(:get, "https://api.trello.com/1/members/me?").
16
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
17
- to_return(:status => 200, :headers => {}, :body => user_payload)
15
+ stub_trello_request!(:get, '/members/me?', nil, user_payload)
18
16
 
19
17
  @member = Member.find('me')
20
18
  end
21
19
 
22
20
  context "actions" do
23
21
  it "retrieves a list of actions" do
24
- stub_request(:get, "https://api.trello.com/1/members/me/actions?").
25
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
26
- to_return(:status => 200, :headers => {}, :body => actions_payload)
27
-
22
+ stub_trello_request!(:get, '/members/me/actions?', nil, actions_payload)
28
23
  @member.actions.count.should be > 0
29
24
  end
30
25
  end
31
26
 
32
27
  context "boards" do
33
28
  it "has a list of boards" do
34
- stub_request(:get, "https://api.trello.com/1/members/me/boards/all?").
35
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
36
- to_return(:status => 200, :headers => {}, :body => boards_payload)
37
-
29
+ stub_trello_request!(:get, '/members/me/boards?', { :filter => :all }, boards_payload)
38
30
  boards = @member.boards
39
31
  boards.count.should be > 0
40
32
  end
@@ -42,10 +34,7 @@ module Trello
42
34
 
43
35
  context "organizations" do
44
36
  it "has a list of organizations" do
45
- stub_request(:get, "https://api.trello.com/1/members/me/organizations/all?").
46
- with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
47
- to_return(:status => 200, :headers => {}, :body => orgs_payload)
48
-
37
+ stub_trello_request!(:get, '/members/me/organizations?', { :filter => :all }, orgs_payload)
49
38
  orgs = @member.organizations
50
39
  orgs.count.should be > 0
51
40
  end
data/spec/spec_helper.rb CHANGED
@@ -17,6 +17,15 @@ require 'trello'
17
17
  require 'webmock/rspec'
18
18
 
19
19
  module Helpers
20
+ def stub_trello_request!(http_method, path, data, returning = '')
21
+ uri = Addressable::URI.parse("https://api.trello.com/#{Trello::API_VERSION}#{path}")
22
+ uri.query_values = data.kind_of?(String) ? JSON.parse(data) : data if data
23
+
24
+ stub_request(http_method, uri.to_s).
25
+ with(:headers => {'Accept'=>'*/*', 'Authorization'=>/.*/, 'User-Agent' => /.*/}).
26
+ to_return(:status => 200, :headers => {}, :body => returning)
27
+ end
28
+
20
29
  def user_details
21
30
  {
22
31
  "id" => "abcdef123456789012345678",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-trello
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-01-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yajl-ruby
16
- requirement: &70240457388560 !ruby/object:Gem::Requirement
16
+ requirement: &70096518301420 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70240457388560
24
+ version_requirements: *70096518301420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: oauth
27
- requirement: &70240457399940 !ruby/object:Gem::Requirement
27
+ requirement: &70096518300720 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.4.5
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70240457399940
35
+ version_requirements: *70096518300720
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: addressable
38
- requirement: &70240457481800 !ruby/object:Gem::Requirement
38
+ requirement: &70096518300060 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.2.6
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70240457481800
46
+ version_requirements: *70096518300060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &70240457630780 !ruby/object:Gem::Requirement
49
+ requirement: &70096518299380 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70240457630780
57
+ version_requirements: *70096518299380
58
58
  description: A wrapper around the trello.com API.
59
59
  email: jeremy@tregunna.ca
60
60
  executables: []
@@ -72,7 +72,9 @@ files:
72
72
  - lib/trello/item_state.rb
73
73
  - lib/trello/list.rb
74
74
  - lib/trello/member.rb
75
+ - lib/trello/notification.rb
75
76
  - lib/trello/organization.rb
77
+ - lib/trello/string.rb
76
78
  - lib/trello.rb
77
79
  - README.md
78
80
  - spec/action_spec.rb