troo 0.0.9 → 0.0.10

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/Gemfile.lock +40 -32
  4. data/Guardfile +9 -1
  5. data/README.md +15 -10
  6. data/bin/troo +22 -2
  7. data/config/en.yml +11 -1
  8. data/config/help +16 -0
  9. data/{.trooconf.example → config/trooconf.yml} +4 -2
  10. data/features/add/card.feature +1 -1
  11. data/features/add/comment.feature +1 -1
  12. data/features/add/list.feature +1 -1
  13. data/features/default/board.feature +1 -1
  14. data/features/default/card.feature +1 -1
  15. data/features/default/list.feature +1 -1
  16. data/features/move/card.feature +5 -5
  17. data/features/refresh/board.feature +1 -1
  18. data/features/refresh/card.feature +1 -1
  19. data/features/refresh/list.feature +1 -1
  20. data/features/show/board.feature +11 -3
  21. data/features/show/boards.feature +1 -0
  22. data/features/show/card.feature +7 -7
  23. data/features/show/comment.feature +15 -6
  24. data/features/show/list.feature +3 -1
  25. data/features/status.feature +2 -2
  26. data/features/step_definitions/fabrication_steps.rb +11 -11
  27. data/features/step_definitions/troo_steps.rb +1 -1
  28. data/features/support/cassettes/200_board_by_id.yml +56 -0
  29. data/features/support/cassettes/200_card_by_id.yml +77 -0
  30. data/features/support/cassettes/200_create_board.yml +186 -0
  31. data/features/support/cassettes/200_create_card.yml +86 -0
  32. data/features/support/cassettes/200_create_comment.yml +73 -0
  33. data/features/support/cassettes/200_create_list.yml +53 -0
  34. data/{test/cassettes/list_by_id.yml → features/support/cassettes/200_list_by_id.yml} +6 -6
  35. data/features/support/cassettes/200_move_card_200_board.yml +86 -0
  36. data/features/support/cassettes/200_move_card_200_list.yml +86 -0
  37. data/features/support/cassettes/200_move_card_400_list.yml +46 -0
  38. data/{test/cassettes/lists_by_board_id.yml → features/support/cassettes/400_board_by_id.yml} +10 -10
  39. data/features/support/cassettes/400_card_by_id.yml +46 -0
  40. data/features/support/cassettes/400_create_card.yml +46 -0
  41. data/features/support/cassettes/400_create_comment.yml +46 -0
  42. data/features/support/cassettes/400_create_list.yml +46 -0
  43. data/features/support/cassettes/400_list_by_id.yml +46 -0
  44. data/features/support/cassettes/400_move_card_200_list.yml +46 -0
  45. data/features/support/cassettes/400_move_card_400_board.yml +46 -0
  46. data/features/support/cassettes/boards_all.yml +286 -0
  47. data/features/support/env.rb +1 -2
  48. data/lib/troo/cli/commands/refresh/all.rb +2 -0
  49. data/lib/troo/cli/main.rb +2 -23
  50. data/lib/troo/configuration.rb +5 -0
  51. data/lib/troo/database.rb +29 -0
  52. data/lib/troo/decorators/resource.rb +24 -10
  53. data/lib/troo/helpers/model_helpers.rb +3 -2
  54. data/lib/troo/models/board.rb +1 -1
  55. data/lib/troo/models/card.rb +1 -1
  56. data/lib/troo/models/comment.rb +0 -4
  57. data/lib/troo/models/list.rb +1 -1
  58. data/lib/troo/presentation/formatter.rb +99 -4
  59. data/lib/troo/presentation/template.rb +8 -9
  60. data/lib/troo/presenters/board.rb +24 -26
  61. data/lib/troo/presenters/card.rb +3 -1
  62. data/lib/troo/presenters/list.rb +30 -17
  63. data/lib/troo/presenters/resource.rb +90 -0
  64. data/lib/troo/retrieval/local.rb +5 -1
  65. data/lib/troo/troo.rb +2 -0
  66. data/lib/troo/version.rb +1 -1
  67. data/lib/troo.rb +7 -4
  68. data/test/cassettes/create_board.yml +15 -9
  69. data/test/cassettes/create_card.yml +10 -10
  70. data/test/cassettes/create_comment.yml +9 -9
  71. data/test/cassettes/create_list.yml +5 -5
  72. data/test/cassettes/move_card_board.yml +11 -11
  73. data/test/cassettes/move_card_list.yml +11 -11
  74. data/test/lib/troo/api/endpoints_test.rb +2 -2
  75. data/test/lib/troo/cli/commands/add_test.rb +2 -2
  76. data/test/lib/troo/cli/commands/refresh/all_test.rb +4 -9
  77. data/test/lib/troo/cli/main_test.rb +0 -25
  78. data/test/lib/troo/configuration_test.rb +18 -13
  79. data/test/lib/troo/decorators/member_test.rb +0 -27
  80. data/test/lib/troo/decorators/resource_test.rb +0 -32
  81. data/test/lib/troo/helpers/model_helpers_test.rb +15 -3
  82. data/test/lib/troo/models/board_test.rb +45 -1
  83. data/test/lib/troo/models/card_test.rb +60 -6
  84. data/test/lib/troo/models/comment_test.rb +44 -4
  85. data/test/lib/troo/models/database_test.rb +19 -0
  86. data/test/lib/troo/models/list_test.rb +46 -2
  87. data/test/lib/troo/models/member_test.rb +51 -1
  88. data/test/lib/troo/presentation/formatter_test.rb +54 -2
  89. data/test/lib/troo/presentation/template_test.rb +4 -4
  90. data/test/lib/troo/presenters/board_test.rb +4 -3
  91. data/test/lib/troo/presenters/list_test.rb +3 -3
  92. data/test/lib/troo/presenters/member_test.rb +1 -1
  93. data/test/lib/troo/presenters/resource_test.rb +79 -0
  94. data/test/lib/troo/remote/board_test.rb +5 -8
  95. data/test/lib/troo/remote/card_test.rb +7 -11
  96. data/test/lib/troo/remote/comment_test.rb +10 -14
  97. data/test/lib/troo/remote/list_test.rb +5 -9
  98. data/test/lib/troo/remote/member_test.rb +5 -9
  99. data/test/lib/troo/remote/persistence/card_test.rb +1 -1
  100. data/test/lib/troo/remote/persistence/comment_test.rb +1 -1
  101. data/test/lib/troo/remote/persistence/list_test.rb +1 -1
  102. data/test/lib/troo/remote/persistence/move_card_test.rb +3 -3
  103. data/test/lib/troo/retrieval/local_test.rb +13 -1
  104. data/test/lib/troo/retrieval/remote_test.rb +1 -1
  105. data/test/support/fabrication.rb +12 -12
  106. data/test/support/fake_trello/fake_response.rb +18 -1
  107. data/test/support/fake_trello/server.rb +2 -0
  108. data/test/support/remotes/all_boards.json +103 -4
  109. data/test/support/remotes/{board.json → all_boards_200.json} +13 -13
  110. data/test/support/remotes/board_200.json +140 -0
  111. data/test/support/remotes/board_by_id.json +9 -9
  112. data/test/support/remotes/board_by_id_200.json +75 -0
  113. data/test/support/remotes/card.json +4 -4
  114. data/test/support/remotes/card_200.json +40 -0
  115. data/test/support/remotes/card_by_card_id.json +64 -64
  116. data/test/support/remotes/card_by_card_id_200.json +302 -0
  117. data/test/support/remotes/comment.json +6 -6
  118. data/test/support/remotes/comment_200.json +27 -0
  119. data/test/support/remotes/create_board.json +1 -1
  120. data/test/support/remotes/create_board_200.json +38 -0
  121. data/test/support/remotes/list.json +2 -2
  122. data/test/support/remotes/list_200.json +7 -0
  123. data/test/support/remotes/member.json +4 -4
  124. data/test/support/remotes/member_200.json +50 -0
  125. data/test/test_helper.rb +9 -2
  126. data/troo.gemspec +4 -3
  127. metadata +92 -41
  128. data/test/cassettes/board_by_id.yml +0 -50
  129. data/test/cassettes/boards_all.yml +0 -50
  130. data/test/cassettes/card_by_id.yml +0 -49
  131. data/test/cassettes/cards_by_board_id.yml +0 -49
  132. data/test/cassettes/cards_by_list_id.yml +0 -49
  133. data/test/cassettes/comments_by_board_id.yml +0 -49
  134. data/test/cassettes/comments_by_card_id.yml +0 -49
  135. data/test/cassettes/member_by_id.yml +0 -48
  136. data/test/cassettes/members_by_board_id.yml +0 -48
  137. data/test/lib/troo/decorators/card_test.rb +0 -113
@@ -0,0 +1,286 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.trello.com/1/members/me/boards
6
+ body:
7
+ encoding: UTF-8
8
+ string: filter=open
9
+ headers:
10
+ Accept:
11
+ - "*/*; q=0.5, application/xml"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ Authorization:
15
+ - "<OAuth Credentials>"
16
+ Content-Length:
17
+ - '11'
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: 'OK '
24
+ headers:
25
+ Content-Type:
26
+ - text/html;charset=utf-8
27
+ Content-Length:
28
+ - '3260'
29
+ X-Xss-Protection:
30
+ - 1; mode=block
31
+ X-Content-Type-Options:
32
+ - nosniff
33
+ X-Frame-Options:
34
+ - SAMEORIGIN
35
+ Server:
36
+ - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24) OpenSSL/1.0.1f
37
+ Date:
38
+ - Mon, 24 Mar 2014 19:05:25 GMT
39
+ Connection:
40
+ - Keep-Alive
41
+ body:
42
+ encoding: UTF-8
43
+ string: |-
44
+ [{
45
+ "id": "20010",
46
+ "name": "My Test Board",
47
+ "desc": "A very brief description...",
48
+ "descData": null,
49
+ "closed": false,
50
+ "idOrganization": null,
51
+ "pinned": true,
52
+ "url": "<Trello URL>",
53
+ "shortUrl": "<Trello URL>",
54
+ "prefs": {
55
+ "permissionLevel": "private",
56
+ "voting": "disabled",
57
+ "comments": "members",
58
+ "invitations": "members",
59
+ "selfJoin": false,
60
+ "cardCovers": true,
61
+ "cardAging": "regular",
62
+ "background": "blue",
63
+ "backgroundColor": "#23719F",
64
+ "backgroundImage": null,
65
+ "backgroundImageScaled": null,
66
+ "backgroundTile": false,
67
+ "backgroundBrightness": "unknown",
68
+ "canBePublic": true,
69
+ "canBeOrg": true,
70
+ "canBePrivate": true,
71
+ "canInvite": true
72
+ },
73
+ "labelNames": {
74
+ "yellow": "Analysis Complete",
75
+ "red": "",
76
+ "purple": "",
77
+ "orange": "",
78
+ "green": "Ready to Pull",
79
+ "blue": ""
80
+ },
81
+ "cards": [
82
+ {
83
+ "id": "20020",
84
+ "checkItemStates": [],
85
+ "closed": true,
86
+ "dateLastActivity": "2013-10-27T22:10:19.584Z",
87
+ "desc": "",
88
+ "descData": null,
89
+ "idBoard": "20010",
90
+ "idList": "20040",
91
+ "idMembersVoted": [],
92
+ "idShort": 1,
93
+ "idAttachmentCover": null,
94
+ "manualCoverAttachment": false,
95
+ "name": "Command: config",
96
+ "pos": 327679,
97
+ "shortLink": "1G0cGaRV",
98
+ "badges": {
99
+ "votes": 0,
100
+ "viewingMemberVoted": false,
101
+ "subscribed": false,
102
+ "fogbugz": "",
103
+ "checkItems": 0,
104
+ "checkItemsChecked": 0,
105
+ "comments": 0,
106
+ "attachments": 0,
107
+ "description": false,
108
+ "due": null
109
+ },
110
+ "due": null,
111
+ "idChecklists": [],
112
+ "idMembers": [],
113
+ "labels": [],
114
+ "shortUrl": "<Trello URL>",
115
+ "subscribed": false,
116
+ "url": "<Trello URL>"
117
+ },
118
+ {
119
+ "id": "20021",
120
+ "checkItemStates": [],
121
+ "closed": false,
122
+ "dateLastActivity": "2014-02-07T19:39:15.075Z",
123
+ "desc": "A description to get us started.",
124
+ "descData": null,
125
+ "idBoard": "20010",
126
+ "idList": "20040",
127
+ "idMembersVoted": [],
128
+ "idShort": 27,
129
+ "idAttachmentCover": null,
130
+ "manualCoverAttachment": false,
131
+ "name": "My New Card",
132
+ "pos": 606207,
133
+ "shortLink": "OMnSslgP",
134
+ "badges": {
135
+ "votes": 0,
136
+ "viewingMemberVoted": false,
137
+ "subscribed": false,
138
+ "fogbugz": "",
139
+ "checkItems": 0,
140
+ "checkItemsChecked": 0,
141
+ "comments": 1,
142
+ "attachments": 0,
143
+ "description": true,
144
+ "due": null
145
+ },
146
+ "due": null,
147
+ "idChecklists": [],
148
+ "idMembers": [],
149
+ "labels": [],
150
+ "shortUrl": "<Trello URL>",
151
+ "subscribed": false,
152
+ "url": "<Trello URL>"
153
+ }
154
+ ],
155
+ "members": [
156
+ {
157
+ "id": "20050",
158
+ "avatarHash": "20001",
159
+ "initials": "GL",
160
+ "fullName": "Gavin Laking",
161
+ "username": "gavinlaking1",
162
+ "confirmed": true
163
+ }
164
+ ],
165
+ "lists": [
166
+ {
167
+ "id": "20040",
168
+ "name": "My New List",
169
+ "closed": true,
170
+ "idBoard": "20010",
171
+ "pos": 256,
172
+ "subscribed": false
173
+ },
174
+ {
175
+ "id": "20041",
176
+ "name": "My New List",
177
+ "closed": true,
178
+ "idBoard": "20010",
179
+ "pos": 512,
180
+ "subscribed": false
181
+ }
182
+ ]
183
+ }
184
+ ]
185
+ http_version:
186
+ recorded_at: Mon, 24 Mar 2014 19:05:25 GMT
187
+ - request:
188
+ method: get
189
+ uri: https://api.trello.com/1/boards/20010
190
+ body:
191
+ encoding: UTF-8
192
+ string: cards=open&lists=open&members=all
193
+ headers:
194
+ Accept:
195
+ - "*/*; q=0.5, application/xml"
196
+ Accept-Encoding:
197
+ - gzip, deflate
198
+ Authorization:
199
+ - "<OAuth Credentials>"
200
+ Content-Length:
201
+ - '33'
202
+ User-Agent:
203
+ - Ruby
204
+ response:
205
+ status:
206
+ code: 200
207
+ message: 'OK '
208
+ headers:
209
+ Content-Type:
210
+ - text/html;charset=utf-8
211
+ Content-Length:
212
+ - '2271'
213
+ X-Xss-Protection:
214
+ - 1; mode=block
215
+ X-Content-Type-Options:
216
+ - nosniff
217
+ X-Frame-Options:
218
+ - SAMEORIGIN
219
+ Server:
220
+ - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24) OpenSSL/1.0.1f
221
+ Date:
222
+ - Mon, 24 Mar 2014 19:05:25 GMT
223
+ Connection:
224
+ - Keep-Alive
225
+ body:
226
+ encoding: UTF-8
227
+ string: '{"id":"20010","name":"My Test Board","desc":"A very brief description...","descData":null,"closed":false,"idOrganization":null,"pinned":true,"url":"<Trello
228
+ URL>","shortUrl":"<Trello URL>","prefs":{"permissionLevel":"private","voting":"disabled","comments":"members","invitations":"members","selfJoin":false,"cardCovers":true,"cardAging":"regular","background":"blue","backgroundColor":"#23719F","backgroundImage":null,"backgroundImageScaled":null,"backgroundTile":false,"backgroundBrightness":"unknown","canBePublic":true,"canBeOrg":true,"canBePrivate":true,"canInvite":true},"labelNames":{"yellow":"Analysis
229
+ Complete","red":"","purple":"","orange":"","green":"Ready to Pull","blue":""},"cards":[{"id":"20020","checkItemStates":[],"closed":true,"dateLastActivity":"2013-10-27T22:10:19.584Z","desc":"","descData":null,"idBoard":"20010","idList":"20040","idMembersVoted":[],"idShort":1,"idAttachmentCover":null,"manualCoverAttachment":false,"name":"Command:
230
+ config","pos":327679,"shortLink":"1G0cGaRV","badges":{"votes":0,"viewingMemberVoted":false,"subscribed":false,"fogbugz":"","checkItems":0,"checkItemsChecked":0,"comments":0,"attachments":0,"description":false,"due":null},"due":null,"idChecklists":[],"idMembers":[],"labels":[],"shortUrl":"<Trello
231
+ URL>","subscribed":false,"url":"<Trello URL>"},{"id":"20021","checkItemStates":[],"closed":false,"dateLastActivity":"2014-02-07T19:39:15.075Z","desc":"A
232
+ description to get us started.","descData":null,"idBoard":"20010","idList":"20040","idMembersVoted":[],"idShort":27,"idAttachmentCover":null,"manualCoverAttachment":false,"name":"My
233
+ New Card","pos":606207,"shortLink":"OMnSslgP","badges":{"votes":0,"viewingMemberVoted":false,"subscribed":false,"fogbugz":"","checkItems":0,"checkItemsChecked":0,"comments":1,"attachments":0,"description":true,"due":null},"due":null,"idChecklists":[],"idMembers":[],"labels":[],"shortUrl":"<Trello
234
+ URL>","subscribed":false,"url":"<Trello URL>"}],"members":[{"id":"20050","avatarHash":"20001","initials":"GL","fullName":"Gavin
235
+ Laking","username":"gavinlaking1","confirmed":true}],"lists":[{"id":"20040","name":"My
236
+ New List","closed":true,"idBoard":"20010","pos":256,"subscribed":false},{"id":"20041","name":"My
237
+ New List","closed":true,"idBoard":"20010","pos":512,"subscribed":false}]}'
238
+ http_version:
239
+ recorded_at: Mon, 24 Mar 2014 19:05:25 GMT
240
+ - request:
241
+ method: get
242
+ uri: https://api.trello.com/1/boards/20010/actions
243
+ body:
244
+ encoding: UTF-8
245
+ string: filter=commentCard
246
+ headers:
247
+ Accept:
248
+ - "*/*; q=0.5, application/xml"
249
+ Accept-Encoding:
250
+ - gzip, deflate
251
+ Authorization:
252
+ - "<OAuth Credentials>"
253
+ Content-Length:
254
+ - '18'
255
+ User-Agent:
256
+ - Ruby
257
+ response:
258
+ status:
259
+ code: 200
260
+ message: 'OK '
261
+ headers:
262
+ Content-Type:
263
+ - text/html;charset=utf-8
264
+ Content-Length:
265
+ - '397'
266
+ X-Xss-Protection:
267
+ - 1; mode=block
268
+ X-Content-Type-Options:
269
+ - nosniff
270
+ X-Frame-Options:
271
+ - SAMEORIGIN
272
+ Server:
273
+ - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24) OpenSSL/1.0.1f
274
+ Date:
275
+ - Mon, 24 Mar 2014 19:05:25 GMT
276
+ Connection:
277
+ - Keep-Alive
278
+ body:
279
+ encoding: UTF-8
280
+ string: '{"id":"20010","idMemberCreator":"20050","data":{"board":{"shortLink":"a3RnYKnD","name":"My
281
+ Test Board","id":"20010"},"card":{"shortLink":"UJBK7pil","idShort":8,"name":"My
282
+ Test Card","id":"20020"},"text":"My Test Comment"},"type":"commentCard","date":"2014-02-07T18:02:24.297Z","memberCreator":{"id":"20050","avatarHash":"20001","fullName":"Gavin
283
+ Laking","initials":"GL","username":"gavinlaking1"}}'
284
+ http_version:
285
+ recorded_at: Mon, 24 Mar 2014 19:05:25 GMT
286
+ recorded_with: VCR 2.8.0
@@ -21,9 +21,8 @@ Aruba.process = Aruba::InProcess
21
21
  WebMock.disable_net_connect!
22
22
 
23
23
  VCR.configure do |c|
24
- c.cassette_library_dir = 'features/support/fixtures/cassettes'
24
+ c.cassette_library_dir = 'features/support/cassettes'
25
25
  c.hook_into :webmock
26
- # c.debug_logger = File.open("logs/vcr.log", 'w')
27
26
  c.filter_sensitive_data('<OAuth Credentials>') do |interaction|
28
27
  interaction.request.headers['Authorization'].first
29
28
  end
@@ -29,6 +29,8 @@ module Troo
29
29
  def resources
30
30
  @resources ||= external_ids.map do |id|
31
31
  Retrieval::Remote.fetch(Remote::Board, id, mode: :board)
32
+
33
+ Retrieval::Remote.fetch(Remote::Comment, id, mode: :board)
32
34
  end
33
35
  end
34
36
 
data/lib/troo/cli/main.rb CHANGED
@@ -1,19 +1,6 @@
1
1
  module Troo
2
2
  module CLI
3
3
  class Main < ThorFixes
4
- desc 'init',
5
- 'Prepare to use Troo.'
6
- def init
7
- if File.exist?(destination)
8
- say 'A configuration file already exists in your home ' \
9
- 'directory.'
10
- else
11
- say 'A configuration file does not exist in your home ' \
12
- 'directory, creating one...'
13
- FileUtils.cp(source, destination)
14
- end
15
- end
16
-
17
4
  desc 'status',
18
5
  'Get troo status.'
19
6
  def status
@@ -68,8 +55,8 @@ module Troo
68
55
  'Set board, list or card to be default.'
69
56
  subcommand :default, CLI::Default
70
57
 
71
- desc 'refresh [board|list|card] <id>',
72
- 'Refresh board, list or card with <id>.'
58
+ desc 'refresh [all|board|list|card] (<id>)',
59
+ 'Refresh all local data or board, list or card with <id>.'
73
60
  subcommand :refresh, CLI::Refresh
74
61
 
75
62
  desc 'move <card_id> <list_id> (<board_id>)',
@@ -81,14 +68,6 @@ module Troo
81
68
 
82
69
  private
83
70
 
84
- def source
85
- File.dirname(__FILE__) + '/../.trooconf.example'
86
- end
87
-
88
- def destination
89
- Dir.home + '/.trooconf'
90
- end
91
-
92
71
  def heading(text = '')
93
72
  [Esc.yellow, Esc.underline, text, Esc.reset].join
94
73
  end
@@ -28,6 +28,7 @@ module Troo
28
28
  include Virtus.value_object
29
29
 
30
30
  values do
31
+ attribute :name
31
32
  attribute :api_url
32
33
  attribute :api_key
33
34
  attribute :api_token
@@ -41,6 +42,10 @@ module Troo
41
42
  class << self
42
43
  def load(file, env)
43
44
  new(YAML.load_file(file)[env.to_s])
45
+ rescue Errno::ENOENT
46
+ puts "\nConfiguration cannot be found, please run 'troo init'" \
47
+ " first.\n\n"
48
+ exit(1)
44
49
  end
45
50
  end
46
51
 
@@ -0,0 +1,29 @@
1
+ module Troo
2
+ class Database
3
+ class << self
4
+ def connect(configuration, options = {})
5
+ new(configuration, options).connect
6
+ end
7
+ end
8
+
9
+ def initialize(configuration, options = {})
10
+ @configuration, @options = configuration, options
11
+ end
12
+
13
+ def connect
14
+ Ohm.connect(db: configuration.database)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :configuration
20
+
21
+ def options
22
+ defaults.merge!(@options)
23
+ end
24
+
25
+ def defaults
26
+ {}
27
+ end
28
+ end
29
+ end
@@ -9,12 +9,34 @@ module Troo
9
9
 
10
10
  def title
11
11
  [
12
- brackets(klass.id),
13
- Troo::Formatter.highlight(name, options),
12
+ resource_id,
13
+ resource_title,
14
14
  default
15
15
  ].compact.join(' ') + "\n"
16
16
  end
17
17
 
18
+ def resource_title
19
+ if klass.type == :card
20
+ Troo::Wordwrap.this(name, prune: true)
21
+ else
22
+ Troo::Formatter.highlight(
23
+ Troo::Wordwrap.this(name, prune: true), options)
24
+ end
25
+ end
26
+
27
+ def resource_id
28
+ if klass.type == :card
29
+ brackets(Troo::Formatter.highlight(
30
+ Troo::Wordwrap.this(id), options))
31
+ else
32
+ brackets(id)
33
+ end
34
+ end
35
+
36
+ def id
37
+ (klass.type == :card) ? klass.short_id : klass.id
38
+ end
39
+
18
40
  def description
19
41
  return 'N/A' if klass.description.nil? ||
20
42
  klass.description.empty?
@@ -37,14 +59,6 @@ module Troo
37
59
  klass.list.decorator
38
60
  end
39
61
 
40
- def lists
41
- klass.lists.map { |list| list.decorator }
42
- end
43
-
44
- def cards
45
- klass.cards.map { |card| card.decorator }
46
- end
47
-
48
62
  def comments
49
63
  if klass.comments.any? && klass.comments.size > 3
50
64
  msg = '(There are more comments, use: ' \
@@ -20,8 +20,9 @@ module Troo
20
20
  !!(default)
21
21
  end
22
22
 
23
- def count
24
- all.count
23
+ def count(criteria = {})
24
+ return all.count if criteria.empty?
25
+ find(criteria).size
25
26
  end
26
27
 
27
28
  def by_external_id(id)
@@ -39,7 +39,7 @@ module Troo
39
39
  end
40
40
 
41
41
  def presenter(options = {})
42
- Presenters::Board.new(decorator, options)
42
+ Presenters::Board.new(self, options)
43
43
  end
44
44
 
45
45
  def type
@@ -73,7 +73,7 @@ module Troo
73
73
  end
74
74
 
75
75
  def presenter(options = {})
76
- Presenters::Card.new(decorator, options)
76
+ Presenters::Card.new(self, options)
77
77
  end
78
78
 
79
79
  def comment_presenter(options = {})
@@ -44,10 +44,6 @@ module Troo
44
44
  Decorators::Resource.new(self, options)
45
45
  end
46
46
 
47
- # def presenter(options = {})
48
- # Presenters::Comment.new(decorator, options)
49
- # end
50
-
51
47
  def default?
52
48
  false
53
49
  end
@@ -41,7 +41,7 @@ module Troo
41
41
  end
42
42
 
43
43
  def presenter(options = {})
44
- Presenters::List.new(decorator, options)
44
+ Presenters::List.new(self, options)
45
45
  end
46
46
 
47
47
  def type
@@ -11,6 +11,7 @@ module Troo
11
11
  attribute :pad, Integer, default: 0
12
12
  attribute :char, String, default: ' '
13
13
  attribute :width, Integer, default: 80
14
+ attribute :prune, Boolean, default: false
14
15
  end
15
16
  end
16
17
 
@@ -70,10 +71,7 @@ module Troo
70
71
  end
71
72
 
72
73
  def wordwrap
73
- formatted_value
74
- .gsub(/\n/, ' ')
75
- .gsub(/(.{1,#{options.align.width}})(\s+|$)/, "\\1\n")
76
- .strip
74
+ Wordwrap.this(formatted_value, width: width)
77
75
  end
78
76
 
79
77
  private
@@ -90,6 +88,10 @@ module Troo
90
88
  }
91
89
  end
92
90
 
91
+ def width
92
+ options.align.width
93
+ end
94
+
93
95
  def position
94
96
  options.align.pos
95
97
  end
@@ -103,6 +105,89 @@ module Troo
103
105
  end
104
106
  end
105
107
 
108
+ class Wordwrap
109
+ class << self
110
+ def this(value, options = {})
111
+ new(value, options).reformat
112
+ end
113
+ end
114
+
115
+ def initialize(value, options = {})
116
+ @value, @options = value, options
117
+ end
118
+
119
+ def reformat
120
+ return pruned if prune?
121
+ wordwrapped
122
+ end
123
+
124
+ def wordwrapped
125
+ processed = []
126
+ value.split(/\n/).map do |unprocessed|
127
+ line_length = 0
128
+ reformatted = []
129
+
130
+ unprocessed.split(/\s/).map do |word|
131
+ word_length = word.length + 1
132
+
133
+ if (line_length += word_length) >= maximum_width
134
+ line_length = word_length
135
+ processed << reformatted
136
+ reformatted = []
137
+ end
138
+
139
+ reformatted << word
140
+ end
141
+
142
+ processed << reformatted
143
+ end
144
+
145
+ output(processed)
146
+ end
147
+
148
+ private
149
+
150
+ attr_reader :value, :options
151
+
152
+ def output(paragraph)
153
+ paragraph.reduce([]) do |output, line|
154
+ output << line.join(' ')
155
+ end.join("\n")
156
+ end
157
+
158
+ def pruned
159
+ return value if value.size <= pruned_width
160
+ [
161
+ value.chomp.slice(0..pruned_width),
162
+ '...',
163
+ Esc.reset
164
+ ].join
165
+ end
166
+
167
+ def pruned_width
168
+ maximum_width - 3
169
+ end
170
+
171
+ def prune?
172
+ options.fetch(:prune)
173
+ end
174
+
175
+ def maximum_width
176
+ options.fetch(:width)
177
+ end
178
+
179
+ def options
180
+ defaults.merge!(@options)
181
+ end
182
+
183
+ def defaults
184
+ {
185
+ width: 70,
186
+ prune: false
187
+ }
188
+ end
189
+ end
190
+
106
191
  class Output
107
192
  attr_accessor :count
108
193
 
@@ -115,6 +200,16 @@ module Troo
115
200
  nil
116
201
  end
117
202
 
203
+ def spacer(&block)
204
+ if block_given?
205
+ print "\n"
206
+ yield
207
+ print "\n"
208
+ else
209
+ print "\n"
210
+ end
211
+ end
212
+
118
213
  def indent(&block)
119
214
  @count += 1
120
215
 
@@ -3,26 +3,25 @@ module Troo
3
3
  include DecoratorHelpers
4
4
 
5
5
  class << self
6
- def parse(object, template_path)
7
- new(object, template_path).parse
6
+ def parse(object, path)
7
+ new(object, path).parse
8
8
  end
9
9
  end
10
10
 
11
- def initialize(object, template_path)
12
- @object = object
13
- @template_path = template_path
11
+ def initialize(object, path)
12
+ @object, @path = object, path
14
13
  end
15
14
 
16
15
  def parse
17
- ERB.new(load_template, nil, '-').result(binding)
16
+ ERB.new(load, nil, '-').result(binding)
18
17
  end
19
18
 
20
19
  private
21
20
 
22
- attr_reader :object, :template_path
21
+ attr_reader :object, :path
23
22
 
24
- def load_template
25
- File.read(File.dirname(__FILE__) + template_path)
23
+ def load
24
+ File.read(File.dirname(__FILE__) + path)
26
25
  end
27
26
  end
28
27
  end