trello-fs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/Gemfile +3 -0
  4. data/README.md +52 -0
  5. data/examples/demo_board/A_List_of_Cards/README.md +6 -0
  6. data/examples/demo_board/A_List_of_Cards/TrelloFs_Features.md +14 -0
  7. data/examples/demo_board/A_List_of_Cards/TrelloFs_Installation.md +37 -0
  8. data/examples/demo_board/A_Second_List_of_Cards/A_card_with_an_image.md +13 -0
  9. data/examples/demo_board/A_Second_List_of_Cards/README.md +6 -0
  10. data/examples/demo_board/A_Second_List_of_Cards/This_one_has_a_puppy.md +13 -0
  11. data/examples/demo_board/Attachments/A_card_with_an_image/cats-cute-cat-animal-cute-grass-photo.jpg +0 -0
  12. data/examples/demo_board/Attachments/This_one_has_a_puppy/Puppy_2.jpg +0 -0
  13. data/examples/demo_board/Home +13 -0
  14. data/examples/demo_board/Labels/cats.md +5 -0
  15. data/examples/demo_board/Labels/images.md +6 -0
  16. data/examples/demo_board/Labels/no_name.md +4 -0
  17. data/examples/demo_board/Labels/puppies.md +5 -0
  18. data/examples/demo_board/Labels/readme.md +6 -0
  19. data/examples/demo_board/README.md +13 -0
  20. data/examples/demo_board.rb +8 -0
  21. data/examples/welcome_board/Advanced/Get_the_apps_for_iOS_Android_and_Windows_8.md +12 -0
  22. data/examples/welcome_board/Advanced/Need_help.md +10 -0
  23. data/examples/welcome_board/Advanced/README.md +10 -0
  24. data/examples/welcome_board/Advanced/Use_as_many_boards_as_you_want.md +8 -0
  25. data/examples/welcome_board/Advanced/Want_tips_usage_examples_or_API_info.md +8 -0
  26. data/examples/welcome_board/Advanced/Want_to_use_keyboard_shortcuts_We_have_them.md +10 -0
  27. data/examples/welcome_board/Advanced/Want_updates_on_new_features.md +14 -0
  28. data/examples/welcome_board/Attachments/You_can_attach_pictures_and_files/taco.png +0 -0
  29. data/examples/welcome_board/Basics/Click_on_a_card_to_see_whats_behind_it.md +8 -0
  30. data/examples/welcome_board/Basics/README.md +10 -0
  31. data/examples/welcome_board/Basics/This_is_a_card.md +8 -0
  32. data/examples/welcome_board/Basics/Welcome_to_Trello.md +8 -0
  33. data/examples/welcome_board/Basics/You_can_attach_pictures_and_files.md +13 -0
  34. data/examples/welcome_board/Basics/any_kind_of_hyperlink_.md +8 -0
  35. data/examples/welcome_board/Basics/or_checklists.md +8 -0
  36. data/examples/welcome_board/Home +31 -0
  37. data/examples/welcome_board/Intermediate/Drag_people_onto_a_card_to_indicate_that_theyre_responsible_for_it.md +8 -0
  38. data/examples/welcome_board/Intermediate/Finished_with_a_card_Archive_it.md +12 -0
  39. data/examples/welcome_board/Intermediate/Invite_your_team_to_this_board_using_the_Add_Members_button.md +8 -0
  40. data/examples/welcome_board/Intermediate/Make_as_many_lists_as_you_need.md +8 -0
  41. data/examples/welcome_board/Intermediate/README.md +11 -0
  42. data/examples/welcome_board/Intermediate/Try_dragging_cards_anywhere.md +8 -0
  43. data/examples/welcome_board/Intermediate/Use_color-coded_labels_for_organization.md +8 -0
  44. data/examples/welcome_board/Intermediate/You_can_change_the_board_background.md +8 -0
  45. data/examples/welcome_board/Labels/no_name.md +4 -0
  46. data/examples/welcome_board/Labels/red_one.md +6 -0
  47. data/examples/welcome_board/README.md +31 -0
  48. data/examples/welcome_board.rb +8 -0
  49. data/lib/trello-fs/attachment_builder.rb +60 -0
  50. data/lib/trello-fs/attachment_cleaner.rb +39 -0
  51. data/lib/trello-fs/board_builder.rb +61 -0
  52. data/lib/trello-fs/builder.rb +31 -0
  53. data/lib/trello-fs/card_builder.rb +87 -0
  54. data/lib/trello-fs/label_builder.rb +60 -0
  55. data/lib/trello-fs/labels_builder.rb +16 -0
  56. data/lib/trello-fs/list_builder.rb +68 -0
  57. data/lib/trello-fs/repository.rb +36 -0
  58. data/lib/trello-fs/repository_cleaner.rb +18 -0
  59. data/lib/trello-fs/string_to_file_name.rb +9 -0
  60. data/lib/trello-fs/trello_api.rb +83 -0
  61. data/lib/trello-fs/version.rb +3 -0
  62. data/lib/trello-fs.rb +8 -0
  63. data/spec/helpers/test_repository.rb +21 -0
  64. data/spec/spec_helper.rb +9 -0
  65. data/spec/trello-fs/attachment_builder_spec.rb +37 -0
  66. data/spec/trello-fs/attachment_cleaner_spec.rb +44 -0
  67. data/spec/trello-fs/board_builder_spec.rb +28 -0
  68. data/spec/trello-fs/card_builder_spec.rb +60 -0
  69. data/spec/trello-fs/label_builder_spec.rb +36 -0
  70. data/spec/trello-fs/list_builder_spec.rb +32 -0
  71. data/spec/trello-fs/repository_spec.rb +9 -0
  72. data/spec/trello-fs/string_to_file_name_spec.rb +19 -0
  73. data/spec/trello-fs/trello_api_spec.rb +144 -0
  74. data/trello-fs.gemspec +24 -0
  75. metadata +170 -0
@@ -0,0 +1,60 @@
1
+ require 'open-uri'
2
+
3
+ module TrelloFs
4
+ class AttachmentBuilder
5
+ attr_reader :card_builder, :attachment
6
+
7
+ def initialize(card_builder, attachment)
8
+ @card_builder = card_builder
9
+ @attachment = attachment
10
+ end
11
+
12
+ def build
13
+ return if already_downloaded?
14
+
15
+ download_and_save
16
+ end
17
+
18
+ def download_and_save
19
+ data = download
20
+ return unless data
21
+
22
+ FileUtils.mkpath(full_folder_path) unless File.exist? full_folder_path
23
+ File.open(path, 'wb') do |file|
24
+ file.write data
25
+ end
26
+ end
27
+
28
+ def path
29
+ File.join(full_folder_path, file_name)
30
+ end
31
+
32
+ def relative_path
33
+ File.join(folder_path, file_name)
34
+ end
35
+
36
+ def folder_path
37
+ File.join('Attachments', StringToFileName.convert(@card_builder.card_name))
38
+ end
39
+
40
+ def full_folder_path
41
+ File.join(repository.path, folder_path)
42
+ end
43
+
44
+ def file_name
45
+ @attachment.name.gsub(/ /, '_')
46
+ end
47
+
48
+ def already_downloaded?
49
+ File.exist? path
50
+ end
51
+
52
+ def download
53
+ open(@attachment.url).read
54
+ end
55
+
56
+ def repository
57
+ @card_builder.repository
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,39 @@
1
+ require 'fileutils'
2
+ require 'set'
3
+
4
+ module TrelloFs
5
+ class AttachmentCleaner
6
+ def initialize(repository, board)
7
+ @repository = repository
8
+ @board = board
9
+ end
10
+
11
+ def set_of_attachment_paths
12
+ @board.attachments.map do |attachment|
13
+ AttachmentBuilder.new(
14
+ CardBuilder.new(
15
+ ListBuilder.new(
16
+ BoardBuilder.new(@repository, @board),
17
+ attachment.card.list
18
+ ), attachment.card
19
+ ), attachment).path
20
+ end.to_set
21
+ end
22
+
23
+ def remove_old_attachments
24
+ new_attachments = set_of_attachment_paths
25
+
26
+ Dir.
27
+ glob(File.join(@repository.path, "Attachments/**/*")).
28
+ reject {|fn| File.directory?(fn) }.
29
+ each do |file|
30
+ next if new_attachments.include? file
31
+ FileUtils.rm(file)
32
+
33
+ # remove parent dir if empty
34
+ dirname = File.dirname(file)
35
+ FileUtils.rm_rf(dirname) if Dir[File.join(dirname, '*')].empty?
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,61 @@
1
+ module TrelloFs
2
+ class BoardBuilder
3
+ attr_reader :repository, :board
4
+
5
+ def initialize(repository, board)
6
+ @repository = repository
7
+ @board = board
8
+ end
9
+
10
+ def build
11
+ board.lists.each do |list|
12
+ ListBuilder.new(self, list).build
13
+ end
14
+ LabelsBuilder.new(@repository, @board).build
15
+
16
+ build_readme
17
+ end
18
+
19
+ def build_readme
20
+ readme_path = File.join(path, 'README.md')
21
+ File.open(readme_path, 'w') do |file|
22
+ file.write(readme_content)
23
+ end
24
+ end
25
+
26
+ def readme_content
27
+ [
28
+ "# [#{board_name}](#{@board.url})",
29
+ labels_content,
30
+ board.lists.map do |list|
31
+ list_builder = ListBuilder.new(self, list)
32
+ list_link = "[#{list_builder.list_name}](#{list_builder.file_name}/README.md)"
33
+
34
+ [
35
+ "## #{list_link}",
36
+ list_builder.content(true)
37
+ ].join("\n\n")
38
+ end.join("\n\n")
39
+ ].join("\n\n")
40
+ end
41
+
42
+ def labels_content
43
+ return '' unless @board.labels && @board.labels.any?
44
+
45
+ @board.labels.sort {|a, b| a.name <=> b.name }.
46
+ select {|lbl| lbl.cards.any? }.
47
+ map do |label|
48
+ label_builder = LabelBuilder.new(LabelsBuilder.new(@repository, @board), label)
49
+ "[`#{label_builder.label_name}`](#{label_builder.relative_path})"
50
+ end.join(' ')
51
+ end
52
+
53
+ def path
54
+ @repository.path
55
+ end
56
+
57
+ def board_name
58
+ @board.name
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,31 @@
1
+ module TrelloFs
2
+ class Builder
3
+ attr_reader :config
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def build
10
+ repository = Repository.new config, self
11
+ board = TrelloApi.new(repository).board
12
+
13
+ # remove old files from the repo
14
+ RepositoryCleaner.new(repository).clean
15
+
16
+ BoardBuilder.new(repository, board).build
17
+ copy_readme_to_home(repository)
18
+
19
+ # remove old attachments
20
+ AttachmentCleaner.new(repository, board).remove_old_attachments
21
+ end
22
+
23
+ def copy_readme_to_home(repository)
24
+ FileUtils.cp(File.join(repository.path, 'README.md'), File.join(repository.path, 'Home'))
25
+ end
26
+
27
+ def trello_api_board(repository)
28
+ Trello::Board.find(repository.board_id)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ module TrelloFs
2
+ class CardBuilder
3
+ def initialize(list_builder, card)
4
+ @card = card
5
+ @list_builder = list_builder
6
+ end
7
+
8
+ def build
9
+ @list_builder.build_path
10
+
11
+ attachment_paths = @card.attachments.map do |attachment|
12
+ attachment_builder = AttachmentBuilder.new(self, attachment)
13
+ attachment_builder.build
14
+ attachment_builder.relative_path
15
+ end
16
+
17
+ File.open(path, 'w') do |file|
18
+ file.write(content(attachment_paths))
19
+ end
20
+ end
21
+
22
+ def path
23
+ File.join(@list_builder.path, file_name)
24
+ end
25
+
26
+ def relative_path
27
+ File.join(@list_builder.file_name, file_name)
28
+ end
29
+
30
+ def file_name
31
+ "#{StringToFileName.convert(@card.name)}.md"
32
+ end
33
+
34
+ def content(attachment_paths = [])
35
+ labels = card_labels.map do |lbl|
36
+ label_builder = LabelBuilder.new(LabelsBuilder.new(repository, board), lbl)
37
+ "[`#{label_builder.label_name}`](../#{label_builder.relative_path})"
38
+ end.sort.join(' ')
39
+ list_name = @list_builder.list_name
40
+ board_name = @list_builder.board_name
41
+
42
+ [
43
+ "# [#{card_name}](#{@card.url})",
44
+ [
45
+ "[#{board_name}](../README.md)",
46
+ "[#{list_name}](README.md)"
47
+ ].join(' > '),
48
+ labels,
49
+ @card.desc,
50
+ attachments_content(attachment_paths)
51
+ ].join("\n\n")
52
+ end
53
+
54
+ def attachments_content(attachment_paths = [])
55
+ return '' unless attachment_paths.any?
56
+
57
+ links = attachment_paths.map do |path|
58
+ name = path.split('/').last
59
+ path = "../#{path}"
60
+ link = "[#{name}](#{path})"
61
+ if path.end_with?('.png') || path.end_with?('.jpg') || path.end_with?('gif')
62
+ "!#{link}"
63
+ else
64
+ link
65
+ end
66
+ end.join(" \n")
67
+
68
+ "\n\n## Attachments\n\n#{links}"
69
+ end
70
+
71
+ def card_name
72
+ @card.name
73
+ end
74
+
75
+ def repository
76
+ @list_builder.repository
77
+ end
78
+
79
+ def card_labels
80
+ @card_labels ||= @card.labels
81
+ end
82
+
83
+ def board
84
+ @list_builder.board_builder.board
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,60 @@
1
+ module TrelloFs
2
+ class LabelBuilder
3
+ def initialize(labels_builder, label)
4
+ @labels_builder = labels_builder
5
+ @repository = @labels_builder.repository
6
+ @board = @labels_builder.board
7
+ @label = label
8
+ end
9
+
10
+ def build
11
+ FileUtils.mkpath(folder_path)
12
+
13
+ File.open(path, 'w') do |f|
14
+ f.write content
15
+ end
16
+ end
17
+
18
+ def path
19
+ File.join(folder_path, file_name)
20
+ end
21
+
22
+ def relative_path
23
+ File.join('Labels', file_name)
24
+ end
25
+
26
+ def folder_path
27
+ File.join(@repository.path, 'Labels')
28
+ end
29
+
30
+ def file_name
31
+ "#{StringToFileName.convert(label_name)}.md"
32
+ end
33
+
34
+ def content
35
+ [
36
+ "# `#{label_name}`",
37
+ "[#{@board.name}](../README.md)",
38
+ card_links
39
+ ].join("\n\n")
40
+ end
41
+
42
+ def card_links
43
+ @label.cards.sort {|a,b| a.name <=> b.name }.map do |card|
44
+ card_builder = CardBuilder.new(
45
+ ListBuilder.new(
46
+ BoardBuilder.new(@repository, @board),
47
+ card.list
48
+ ), card
49
+ )
50
+ path = '../' + card_builder.relative_path
51
+ link = "[#{card_builder.card_name}](#{path})"
52
+ "- #{link}"
53
+ end.join("\n")
54
+ end
55
+
56
+ def label_name
57
+ @label.name.empty? ? 'no name' : @label.name
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ module TrelloFs
2
+ class LabelsBuilder
3
+ attr_reader :repository, :board
4
+
5
+ def initialize(repository, board)
6
+ @repository = repository
7
+ @board = board
8
+ end
9
+
10
+ def build
11
+ @board.labels.each do |label|
12
+ LabelBuilder.new(self, label).build
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,68 @@
1
+ module TrelloFs
2
+ class ListBuilder
3
+ attr_reader :board_builder, :list
4
+
5
+ def initialize(board_builder, list)
6
+ @board_builder = board_builder
7
+ @list = list
8
+ end
9
+
10
+ def build
11
+ list.cards.each do |card|
12
+ CardBuilder.new(self, card).build
13
+ end
14
+
15
+ build_readme
16
+ end
17
+
18
+ def build_readme
19
+ build_path
20
+ readme_path = File.join(path, 'README.md')
21
+ File.open(readme_path, 'w') do |file|
22
+ file.write(readme_content)
23
+ end
24
+ end
25
+
26
+ def readme_content
27
+ [
28
+ "# #{list_name}",
29
+ "[#{board_name}](../README.md)",
30
+ content
31
+ ].join("\n\n")
32
+ end
33
+
34
+ def content(full_path = false)
35
+ @list.cards.map do |card|
36
+ cb = CardBuilder.new(self, card)
37
+ card_path = cb.file_name
38
+ card_path = File.join(file_name, card_path) if full_path
39
+
40
+ "- [#{cb.card_name}](#{card_path})"
41
+ end.join("\n")
42
+ end
43
+
44
+ def path
45
+ File.join(@board_builder.path, file_name)
46
+ end
47
+
48
+ def file_name
49
+ StringToFileName.convert(@list.name)
50
+ end
51
+
52
+ def build_path
53
+ FileUtils.mkpath(path) unless File.exist? path
54
+ end
55
+
56
+ def list_name
57
+ @list.name
58
+ end
59
+
60
+ def board_name
61
+ @board_builder.board_name
62
+ end
63
+
64
+ def repository
65
+ @board_builder.repository
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ module TrelloFs
2
+ class Repository
3
+ attr_reader :config
4
+
5
+ def initialize(config, builder = nil)
6
+ raise 'Wrong arguments' unless has_required_configuration?(config)
7
+
8
+ @config = config
9
+ @builder = builder
10
+ end
11
+
12
+ def path
13
+ @config[:path]
14
+ end
15
+
16
+ def board_id
17
+ @config[:board_id]
18
+ end
19
+
20
+ def developer_public_key
21
+ config[:developer_public_key]
22
+ end
23
+
24
+ def member_token
25
+ config[:member_token]
26
+ end
27
+
28
+ private
29
+
30
+ def has_required_configuration?(config)
31
+ config.has_key?(:path) &&
32
+ config.has_key?(:developer_public_key) &&
33
+ config.has_key?(:member_token)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+
3
+ module TrelloFs
4
+ class RepositoryCleaner
5
+ def initialize(repository)
6
+ @repository = repository
7
+ end
8
+
9
+ def clean
10
+ Dir.entries(@repository.path).each do |path|
11
+ next if path.start_with? '.'
12
+ next if path == 'Attachments'
13
+
14
+ FileUtils.rm_rf File.join(@repository.path, path)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module TrelloFs
2
+ class StringToFileName
3
+ def self.convert(str)
4
+ str.gsub(/[^\w\s_-]+/, '').
5
+ gsub(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2').
6
+ gsub(/\s+/, '_')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,83 @@
1
+ require 'open-uri'
2
+ require 'json'
3
+
4
+ module TrelloFs
5
+ class TrelloApi
6
+ def initialize(repository)
7
+ @repository = repository
8
+ end
9
+
10
+ def board
11
+ @board ||= new_board
12
+ end
13
+
14
+ def new_board
15
+ json = download_board_json
16
+ board = OpenStruct.new(name: json['name'],
17
+ desc: json['desc'],
18
+ id: json['id'],
19
+ url: json['url'])
20
+ labels, lists = {}, {}
21
+ board.attachments = []
22
+
23
+ board.organization_name = json['organization']['displayName'] if json['organization']
24
+
25
+ json['labels'].each do |label|
26
+ labels[label['id']] = OpenStruct.new name: label['name'], id: label['id'], cards: []
27
+ end
28
+
29
+ json['lists'].each do |list|
30
+ lists[list['id']] = OpenStruct.new(name: list['name'],
31
+ id: list['id'],
32
+ board: board,
33
+ cards: [])
34
+ end
35
+
36
+ cards = json['cards'].map do |card|
37
+ list = lists[card['idList']]
38
+ c = OpenStruct.new(id: card['id'],
39
+ name: card['name'],
40
+ desc: card['desc'],
41
+ url: card['url'],
42
+ list: list)
43
+ list.cards << c
44
+
45
+ c.labels = card['idLabels'].map do |label_id|
46
+ label = labels[label_id]
47
+ label.cards << c
48
+ label
49
+ end
50
+
51
+ c.checklists = card['checklists'].map do |checklist|
52
+ OpenStruct.new(
53
+ name: checklist['name'],
54
+ items: checklist['checkItems'].map do |item|
55
+ OpenStruct.new(name: item['name'], state: item['state'])
56
+ end
57
+ )
58
+ end
59
+
60
+ c.attachments = card['attachments'].map do |attachment|
61
+ a = OpenStruct.new(name: attachment['name'],
62
+ url: attachment['url'],
63
+ id: attachment['id'],
64
+ card: c)
65
+ board.attachments << a
66
+ a
67
+ end
68
+
69
+ c
70
+ end
71
+
72
+ board.labels = labels.values
73
+ board.lists = lists.values
74
+
75
+ board
76
+ end
77
+
78
+ def download_board_json
79
+ url = "https://api.trello.com/1/boards/#{@repository.board_id}?key=#{@repository.developer_public_key}&token=#{@repository.member_token}&cards=all&lists=all&labels=all&card_checklists=all&card_attachments=true&organization=true"
80
+ JSON.parse(open(url).read)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,3 @@
1
+ module TrelloFs
2
+ VERSION = "0.0.1"
3
+ end
data/lib/trello-fs.rb ADDED
@@ -0,0 +1,8 @@
1
+ Dir[File.dirname(__FILE__) + "/**/*.rb"].each { |file| require file }
2
+ require 'fileutils'
3
+
4
+ module TrelloFs
5
+ def self.build(config)
6
+ Builder.new(config).build
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ require 'fileutils'
2
+
3
+ class TestRepository < TrelloFs::Repository
4
+ def initialize
5
+ super({
6
+ path: TestRepository.path,
7
+ developer_public_key: '',
8
+ member_token: ''
9
+ })
10
+ end
11
+
12
+ def self.path
13
+ p = 'tmp/test_repo'
14
+ FileUtils.mkpath p
15
+ p
16
+ end
17
+
18
+ def self.remove
19
+ FileUtils.rm_rf path
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path("../../lib/trello-fs", __FILE__)
2
+ Dir[File.dirname(__FILE__) + "/helpers/*.rb"].each { |file| require file }
3
+ require 'ostruct'
4
+
5
+ RSpec.configure do |config|
6
+ config.after :each do
7
+ TestRepository.remove
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe TrelloFs::AttachmentBuilder do
4
+ let(:attachment) { OpenStruct.new(id: '1', name: 'Attachment Name') }
5
+ let(:card) { OpenStruct.new(name: 'Card Name', attachments: [attachment]) }
6
+ let(:list) { OpenStruct.new(name: 'List Name', cards: [card]) }
7
+ let(:board) { OpenStruct.new(name: 'Board') }
8
+
9
+ let(:board_builder) { TrelloFs::BoardBuilder.new(TestRepository.new, board) }
10
+ let(:list_builder) { TrelloFs::ListBuilder.new(board_builder, list) }
11
+ let(:card_builder) { TrelloFs::CardBuilder.new(list_builder, card) }
12
+ let(:attachment_builder) { TrelloFs::AttachmentBuilder.new(card_builder, attachment) }
13
+
14
+ subject { attachment_builder }
15
+
16
+ before(:each) do
17
+ allow(attachment_builder).to receive(:download) { 'data' }
18
+ end
19
+
20
+ describe '#path' do
21
+ subject { attachment_builder.path }
22
+
23
+ it { should include 'Card_Name' }
24
+ it { should include 'Attachment Name' }
25
+ end
26
+
27
+ describe '#already_downloaded?' do
28
+ subject { attachment_builder.already_downloaded? }
29
+
30
+ it { should eq false }
31
+
32
+ it 'returns true after download' do
33
+ attachment_builder.build
34
+ should eq true
35
+ end
36
+ end
37
+ end