dropdown 0.8.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.
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