ruby-trello 0.2.0 → 0.2.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/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