dropdown 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +194 -0
  7. data/Rakefile +41 -0
  8. data/dropdown.gemspec +37 -0
  9. data/lib/dropdown.rb +23 -0
  10. data/lib/dropdown/blog.rb +23 -0
  11. data/lib/dropdown/configuration.rb +12 -0
  12. data/lib/dropdown/constants.rb +4 -0
  13. data/lib/dropdown/dropbox.rb +1 -0
  14. data/lib/dropdown/dropbox/session.rb +18 -0
  15. data/lib/dropdown/errors.rb +4 -0
  16. data/lib/dropdown/inflector.rb +11 -0
  17. data/lib/dropdown/iterators.rb +3 -0
  18. data/lib/dropdown/iterators/dropbox_iterator.rb +31 -0
  19. data/lib/dropdown/iterators/file_iterator.rb +18 -0
  20. data/lib/dropdown/iterators/iterator_factory.rb +12 -0
  21. data/lib/dropdown/markdown_renderer.rb +21 -0
  22. data/lib/dropdown/output_stores.rb +3 -0
  23. data/lib/dropdown/output_stores/dropbox_store.rb +24 -0
  24. data/lib/dropdown/output_stores/file_store.rb +23 -0
  25. data/lib/dropdown/output_stores/output_store_factory.rb +12 -0
  26. data/lib/dropdown/parsers/excerpt_extractor.rb +38 -0
  27. data/lib/dropdown/parsers/metadata_parser.rb +30 -0
  28. data/lib/dropdown/parsers/parser.rb +12 -0
  29. data/lib/dropdown/post.rb +48 -0
  30. data/lib/dropdown/processor.rb +39 -0
  31. data/lib/dropdown/readers.rb +3 -0
  32. data/lib/dropdown/readers/dropbox_reader.rb +32 -0
  33. data/lib/dropdown/readers/file_reader.rb +13 -0
  34. data/lib/dropdown/readers/reader_factory.rb +12 -0
  35. data/lib/dropdown/renderer_factory.rb +10 -0
  36. data/lib/dropdown/version.rb +3 -0
  37. data/spec/dropdown/blog_spec.rb +62 -0
  38. data/spec/dropdown/configuration_spec.rb +12 -0
  39. data/spec/dropdown/dropbox/session_spec.rb +26 -0
  40. data/spec/dropdown/inflector_spec.rb +18 -0
  41. data/spec/dropdown/iterators/dropbox_iterator_spec.rb +53 -0
  42. data/spec/dropdown/iterators/file_iterator_spec.rb +43 -0
  43. data/spec/dropdown/iterators/iterator_factory_spec.rb +10 -0
  44. data/spec/dropdown/markdown_renderer_spec.rb +31 -0
  45. data/spec/dropdown/output_stores/dropbox_store_spec.rb +46 -0
  46. data/spec/dropdown/output_stores/file_store_spec.rb +31 -0
  47. data/spec/dropdown/output_stores/output_store_factory_spec.rb +9 -0
  48. data/spec/dropdown/parsers/excerpt_extractor_spec.rb +54 -0
  49. data/spec/dropdown/parsers/metadata_parser_spec.rb +35 -0
  50. data/spec/dropdown/parsers/parser_spec.rb +26 -0
  51. data/spec/dropdown/post_spec.rb +66 -0
  52. data/spec/dropdown/processor_spec.rb +80 -0
  53. data/spec/dropdown/readers/dropbox_reader_spec.rb +43 -0
  54. data/spec/dropdown/readers/file_reader_spec.rb +30 -0
  55. data/spec/dropdown/readers/reader_factory_spec.rb +9 -0
  56. data/spec/dropdown/renderer_factory_spec.rb +18 -0
  57. data/spec/dropdown_spec.rb +13 -0
  58. data/spec/features/processing_a_markdown_directory_spec.rb +60 -0
  59. data/spec/fixtures/blog/my-trip-to-africa.md +10 -0
  60. data/spec/fixtures/processed/my-trip-to-africa.html +16 -0
  61. data/spec/fixtures/sample_post.md +8 -0
  62. data/spec/spec_helper.rb +3 -0
  63. data/spec/support/dummy_dropbox.rb +63 -0
  64. metadata +278 -0
@@ -0,0 +1,12 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/dropdown'
3
+
4
+ describe Dropdown::Configuration do
5
+ subject { Dropdown::Configuration.new }
6
+ it 'sets defaults' do
7
+ subject.renderer.should == :markdown_renderer
8
+ subject.dropbox_app_key.should be_nil
9
+ subject.dropbox_app_secret.should be_nil
10
+ subject.dropbox_access_token.should be_nil
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../support/dummy_dropbox'
3
+ require_relative '../../../lib/dropdown/dropbox/session'
4
+
5
+ describe Dropdown::Dropbox::Session do
6
+ let(:app_key) { 'key' }
7
+ let(:app_secret) { 'secret' }
8
+ subject { Dropdown::Dropbox::Session.new app_key, app_secret }
9
+
10
+ describe '#authorize_url' do
11
+ it 'returns the url for the user to authorize Dropbox' do
12
+ subject.authorize_url.should == "https://www.dropbox.com/1/oauth2/authorize?client_id=#{app_key}&response_type=code"
13
+ end
14
+ end
15
+
16
+ describe '#access_token' do
17
+ include DummyDropbox
18
+
19
+ it 'returns the access token based on the authorize code' do
20
+ access_token = "12345678"
21
+
22
+ stub_dropbox_token app_key, app_secret, access_token
23
+ subject.access_token('blah').should == access_token
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/dropdown/inflector'
3
+
4
+ describe Dropdown::Inflector do
5
+ describe '#constant_name' do
6
+ it 'can get a constant name from a symbol' do
7
+ Dropdown::Inflector.new(:test).constant_name.should == 'Test'
8
+ end
9
+
10
+ it 'handles underscores' do
11
+ Dropdown::Inflector.new(:test_this).constant_name.should == 'TestThis'
12
+ end
13
+
14
+ it 'handles nil words' do
15
+ Dropdown::Inflector.new(nil).constant_name.should be_empty
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,53 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../support/dummy_dropbox'
3
+ require_relative '../../../lib/dropdown'
4
+
5
+ describe Dropdown::Iterators::DropboxIterator do
6
+ describe '.initialize' do
7
+ it 'requires a source path' do
8
+ expect{ Dropdown::Iterators::DropboxIterator.new(nil) }.to raise_error ArgumentError
9
+ end
10
+ end
11
+
12
+ describe '.each' do
13
+ include DummyDropbox
14
+
15
+ let(:access_token) { 'blah' }
16
+ let(:dir) { 'Documents/test' }
17
+ before { Dropdown.configure { |c| c.dropbox_access_token = access_token } }
18
+
19
+ it 'iterates over markdown files that end in .md' do
20
+ path = 'Documents/test/test1.md'
21
+ contents = [{is_dir: false, path: path}]
22
+ stub_dropbox_metadata access_token, dir, contents
23
+
24
+ expect{ |f| Dropdown::Iterators::DropboxIterator.new(dir).each(&f) }.to yield_with_args path
25
+ end
26
+
27
+ it 'iterates over markdown files that end in .markdown' do
28
+ path = 'Documents/test/test1.markdown'
29
+ contents = [{is_dir: false, path: path}]
30
+ stub_dropbox_metadata access_token, dir, contents
31
+
32
+ expect{ |f| Dropdown::Iterators::DropboxIterator.new(dir).each(&f) }.to yield_with_args path
33
+ end
34
+
35
+ it 'ignores files that are not markdown files' do
36
+ path = 'Documents/test/test1.txt'
37
+ contents = [{is_dir: false, path: path}]
38
+ stub_dropbox_metadata access_token, dir, contents
39
+
40
+ expect{ |f| Dropdown::Iterators::DropboxIterator.new(dir).each(&f) }.not_to yield_control
41
+ end
42
+
43
+ it 'handles an extra slash in the source' do
44
+ directory = dir + "/"
45
+
46
+ path = 'Documents/test/test1.markdown'
47
+ contents = [{is_dir: false, path: path}]
48
+ stub_dropbox_metadata access_token, dir, contents
49
+
50
+ expect{ |f| Dropdown::Iterators::DropboxIterator.new(directory).each(&f) }.to yield_with_args path
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,43 @@
1
+ require 'tempfile'
2
+ require 'pathname'
3
+ require_relative '../../spec_helper'
4
+ require_relative '../../../lib/dropdown/iterators/file_iterator'
5
+
6
+ describe Dropdown::Iterators::FileIterator do
7
+ describe '.initialize' do
8
+ it 'should require a source path' do
9
+ expect{ Dropdown::Iterators::FileIterator.new(nil) }.to raise_error ArgumentError
10
+ end
11
+ end
12
+
13
+ describe '.each' do
14
+ it 'should iterate over markdown files that end in .md' do
15
+ file = Tempfile.new ['test', '.md']
16
+ dir = Pathname.new(file.path).dirname
17
+ expect{ |f| Dropdown::Iterators::FileIterator.new(dir).each(&f) }.to yield_with_args file.path
18
+ file.delete
19
+ end
20
+
21
+ it 'should iterate over markdown files that end in .markdown' do
22
+ file = Tempfile.new ['test', '.markdown']
23
+ dir = Pathname.new(file.path).dirname
24
+ expect{ |f| Dropdown::Iterators::FileIterator.new(dir).each(&f) }.to yield_with_args file.path
25
+ file.delete
26
+ end
27
+
28
+ it 'should ignore files that are not markdown files' do
29
+ file = Tempfile.new 'test'
30
+ dir = Pathname.new(file.path).dirname
31
+ expect{ |f| Dropdown::Iterators::FileIterator.new(dir).each(&f) }.not_to yield_control
32
+ file.delete
33
+ end
34
+
35
+ it 'should handle an extra slash in the source' do
36
+ file = Tempfile.new ['test', '.markdown']
37
+ dir = "#{Pathname.new(file.path).dirname}/"
38
+ expect{ |f| Dropdown::Iterators::FileIterator.new(dir).each(&f) }.to yield_with_args file.path
39
+ file.delete
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,10 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/dropdown/iterators'
3
+
4
+ describe Dropdown::Iterators::IteratorFactory do
5
+ it 'creates an iterator with a type and a source' do
6
+ iterator = Dropdown::Iterators::IteratorFactory.create :file, 'blah'
7
+ iterator.should be_a Dropdown::Iterators::FileIterator
8
+ end
9
+ end
10
+
@@ -0,0 +1,31 @@
1
+ require 'tempfile'
2
+ require_relative '../spec_helper'
3
+ require_relative '../../lib/dropdown'
4
+
5
+ describe Dropdown::MarkdownRenderer do
6
+ subject { Dropdown::MarkdownRenderer.new(@file.path) }
7
+
8
+ context 'for a local file' do
9
+ before do
10
+ @file = Tempfile.new(['markdown', '.md'])
11
+ @file.write "This is *great*, yo"
12
+ @file.close
13
+ subject.reader = Dropdown::Readers::FileReader.new
14
+ end
15
+ after { @file.unlink }
16
+
17
+ describe '#render' do
18
+ it 'produces html from a markdown file' do
19
+ result = subject.render
20
+ result.should == "<p>This is <em>great</em>, yo</p>\n"
21
+ end
22
+ end
23
+
24
+ describe '#output_filename' do
25
+ it 'produces the file name with the correct extension for input file' do
26
+ filename = File.basename(@file)
27
+ subject.output_filename.should == filename.gsub(/\.md/, '.html')
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../support/dummy_dropbox'
3
+ require_relative '../../../lib/dropdown'
4
+ require_relative '../../../lib/dropdown/output_stores/dropbox_store'
5
+
6
+ describe Dropdown::OutputStores::DropboxStore do
7
+ include DummyDropbox
8
+
9
+ let(:access_token) { 'blah' }
10
+ let(:html) { "<p>This is <em>great</em>, yo</p>\n" }
11
+ let(:output_path) { '/blog/processed' }
12
+ before { Dropdown.configure { |c| c.dropbox_access_token = access_token } }
13
+ after { remove_stubbed_dropbox_files }
14
+
15
+ subject { Dropdown::OutputStores::DropboxStore.new output_path }
16
+
17
+ describe '#save' do
18
+ it 'creates an output directory if it does not exist' do
19
+ filename = 'stuff.html'
20
+ stub_dropbox_put_file access_token, path(filename), html, true
21
+
22
+ subject.save html, filename
23
+ stubbed_dropbox_pathname(subject.path).should exist
24
+ end
25
+
26
+ it 'names the output file the same as the input file' do
27
+ filename = 'bar.html'
28
+ stub_dropbox_put_file access_token, path(filename), html, true
29
+ subject.save html, filename
30
+ output_file = stubbed_dropbox_pathname(File.join(output_path, filename))
31
+ File.exists?(output_file).should be_true
32
+ end
33
+
34
+ it 'writes the content to the file name' do
35
+ filename = 'bar.html'
36
+ stub_dropbox_put_file access_token, path(filename), html, true
37
+ subject.save html, filename
38
+ output_file = stubbed_dropbox_pathname(File.join(output_path, filename))
39
+ File.readlines(output_file)[0].should == html
40
+ end
41
+
42
+ def path(filename)
43
+ File.join(output_path, filename).gsub /^\//, ''
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ require 'pathname'
2
+ require 'tmpdir'
3
+ require_relative '../../spec_helper'
4
+ require_relative '../../../lib/dropdown/output_stores/file_store'
5
+
6
+ describe Dropdown::OutputStores::FileStore do
7
+ let(:html) { "<p>This is <em>great</em>, yo</p>\n" }
8
+ let(:output_path) { File.join(Dir.tmpdir, 'foo') }
9
+ subject { Dropdown::OutputStores::FileStore.new output_path }
10
+
11
+ describe '#save' do
12
+ after { File.delete subject.path }
13
+
14
+ it 'create an output directory if it does not exist' do
15
+ subject.save html, 'stuff.html'
16
+ Pathname.new(subject.path).should exist
17
+ end
18
+
19
+ it 'names the output file the same as the input file' do
20
+ subject.save html, 'bar.html'
21
+ output_file = File.join(output_path, 'bar.html')
22
+ File.exists?(output_file).should be_true
23
+ end
24
+
25
+ it 'writes the content to the file name' do
26
+ subject.save html, 'bar.html'
27
+ output_file = File.join(output_path, 'bar.html')
28
+ File.readlines(output_file)[0].should == html
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/dropdown/output_stores'
3
+
4
+ describe Dropdown::OutputStores::OutputStoreFactory do
5
+ it 'creates an output store with a type and a path' do
6
+ output_store = Dropdown::OutputStores::OutputStoreFactory.create :dropbox, 'blah'
7
+ output_store.should be_a Dropdown::OutputStores::DropboxStore
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/dropdown/parsers/parser'
3
+ require_relative '../../../lib/dropdown/parsers/excerpt_extractor'
4
+
5
+ describe Dropdown::Parsers::ExcerptExtractor do
6
+ describe '#extract' do
7
+ it 'extracts the first 120 characters' do
8
+ subject = Dropdown::Parsers::ExcerptExtractor.new('Hello world')
9
+ subject.extract.should == 'Hello world'
10
+ end
11
+
12
+ it 'extracts only the html content' do
13
+ subject = Dropdown::Parsers::ExcerptExtractor.new('<p>Hello world</p>')
14
+ subject.extract.should == 'Hello world'
15
+ end
16
+
17
+ it 'extracts multiple lines' do
18
+ content = [
19
+ '<p>Hello world</p>',
20
+ '<div>I hope the world is fine</div>'
21
+ ].join
22
+ subject = Dropdown::Parsers::ExcerptExtractor.new content
23
+ subject.extract.should == "Hello world\nI hope the world is fine"
24
+ end
25
+
26
+ it 'ignores comments' do
27
+ content = [
28
+ '<!-- This should be ignored -->',
29
+ '<p>Hello world</p>'
30
+ ].join
31
+ subject = Dropdown::Parsers::ExcerptExtractor.new content
32
+ subject.extract.should == 'Hello world'
33
+ end
34
+
35
+ it 'joins with a blank for non block elements' do
36
+ content = [
37
+ '<p>Hello <strong>world</strong></p>',
38
+ '<div>I hope the world is fine</div>'
39
+ ].join
40
+ subject = Dropdown::Parsers::ExcerptExtractor.new content
41
+ subject.extract.should == "Hello world\nI hope the world is fine"
42
+ end
43
+
44
+ it 'ignores elements that are not html' do
45
+ content = [
46
+ '<p>Hello </p>',
47
+ "\n",
48
+ '<div>world</div>'
49
+ ].join
50
+ subject = Dropdown::Parsers::ExcerptExtractor.new content
51
+ subject.extract.should == "Hello \nworld"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/dropdown/parsers/parser'
3
+ require_relative '../../../lib/dropdown/parsers/metadata_parser'
4
+
5
+ describe Dropdown::Parsers::MetadataParser do
6
+ describe '.initialize' do
7
+
8
+ context 'setting instance variables' do
9
+ subject { Dropdown::Parsers::MetadataParser.new('Hello world') }
10
+
11
+ it 'defaults the headers to an empty hash' do
12
+ subject.headers.should == {}
13
+ end
14
+ end
15
+ end
16
+
17
+ describe '#parse' do
18
+ let(:contents) {
19
+ file_path = File.join(File.dirname(__FILE__),
20
+ '../../fixtures/processed/my-trip-to-africa.html')
21
+ File.new(file_path, 'r').readlines.join
22
+ }
23
+
24
+ subject { Dropdown::Parsers::MetadataParser.new(contents) }
25
+
26
+ it 'creates a header variable for each comment line prior to the body' do
27
+ subject.parse
28
+ subject.headers.should == {
29
+ title: 'My trip to Africa',
30
+ author: 'Jane Goodall',
31
+ date: '4/4/1989'
32
+ }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/dropdown/parsers/parser'
3
+
4
+ class MyParser
5
+ include Dropdown::Parsers::Parser
6
+ end
7
+
8
+ describe Dropdown::Parsers::Parser do
9
+ context 'raising errors' do
10
+ it 'requires some content' do
11
+ expect {
12
+ MyParser.new(nil)
13
+ }.to raise_error ArgumentError
14
+ end
15
+ end
16
+
17
+ context 'setting instance variables' do
18
+ let(:content) { "Hello world" }
19
+
20
+ subject { MyParser.new(content) }
21
+
22
+ it 'sets the content' do
23
+ subject.content.should == content
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../support/dummy_dropbox'
3
+ require_relative '../../lib/dropdown'
4
+
5
+ describe Dropdown::Post do
6
+ let(:current_directory) { File.expand_path File.dirname(__FILE__) }
7
+ let(:processed_file) { File.join current_directory, '../fixtures/processed/my-trip-to-africa.html' }
8
+ subject { Dropdown::Post.new(processed_file, Dropdown::Readers::FileReader.new) }
9
+
10
+ describe '#source' do
11
+ it 'is initialized with a path to an html file' do
12
+ source = 'foo'
13
+ Dropdown::Post.new(source, nil).source.should == source
14
+ end
15
+ end
16
+
17
+ describe 'retrieving metadata' do
18
+ it 'returns the title from the html contents' do
19
+ subject.title.should == 'My trip to Africa'
20
+ end
21
+
22
+ it 'returns the author from the html contents' do
23
+ subject.author.should == 'Jane Goodall'
24
+ end
25
+
26
+ it 'returns the date from the html contents' do
27
+ subject.date.should == Date.parse('4/4/1989')
28
+ end
29
+ end
30
+
31
+ describe '#body' do
32
+ it 'returns the full html' do
33
+ subject.body.should == File.new(processed_file, 'r').readlines.join
34
+ end
35
+ end
36
+
37
+ describe '#excerpt' do
38
+ it 'returns the first 120 characters of the html content' do
39
+ results = "I had so much fun on my trip to Africa.\nHere is just a list of things that I have accomplished:\nRode on an elephant\nTouched a snake\nDid some shopping\nAte some great food\n\nIt was a really good time."
40
+ subject.excerpt.should == results
41
+ end
42
+ end
43
+
44
+ describe 'for a Dropbox file' do
45
+ include DummyDropbox
46
+
47
+ let(:access_token) { 'blah' }
48
+ let(:processed_file) { 'blog/stuff.html' }
49
+ let(:contents) { "<p>Hello <span class='test'>world</span></p>" }
50
+
51
+ subject { Dropdown::Post.new(processed_file, Dropdown::Readers::DropboxReader.new) }
52
+
53
+ before do
54
+ Dropdown.configure { |c| c.dropbox_access_token = access_token }
55
+ stub_dropbox_put_file access_token, processed_file, contents, true
56
+ end
57
+ after { remove_stubbed_dropbox_files }
58
+
59
+ describe '#body' do
60
+ it 'returns the full html' do
61
+ stub_dropbox_get_file access_token, processed_file
62
+ subject.body.should == contents
63
+ end
64
+ end
65
+ end
66
+ end