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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTJjYTZhZWE1ODY2YzkyOTlmOWNmZmYzNGRlM2Q0MmU5YzY3MmVlYQ==
5
+ data.tar.gz: !binary |-
6
+ MTg4MDI4ZmE3ZDE4NWEwNjA3MGEzZTFhOWJiNDJiNzIwOWM2MDMzMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZThiZWJiOGU5MzUwNDk1YWE5NTY1OWZjMTQ4MGRkZTJkMzc5ODExNTg4ZDY2
10
+ OWE0YzVhNGEzYjk0ZTI0ODBkMDMyZTQ3YmMwYWI4ZmM1Zjc5MWRlNjRiMWJh
11
+ Y2ZjY2JiNDU2MDY1YTA1MTlkMDYxYjY5NWU1MmM3ZTYyOGJiNjE=
12
+ data.tar.gz: !binary |-
13
+ MzUyODY0NjE5MTcwMDA4N2M4NTUyMTgzOGNhY2M4NTE5YTZkMGJkNTM0Zjll
14
+ ZTEwNjM2M2RjNzU3ODY3ODQ3ODNjODRjNTcyOTYzMWNkMjI0NjU5MGNkNzE1
15
+ ODhkZGEwODNhMWNkMWM1YjM2MWMzY2RlOGYzNjYyYWI3MWEzYjA=
@@ -0,0 +1,23 @@
1
+ Gemfile.lock
2
+ *.gem
3
+ *.rbc
4
+ .DS_Store
5
+ .bundle
6
+ .config
7
+ coverage
8
+ InstalledFiles
9
+ lib/bundler/man
10
+ pkg
11
+ rdoc
12
+ spec/reports
13
+ test/tmp
14
+ test/version_tmp
15
+ tmp
16
+
17
+ # YARD artifacts
18
+ .yardoc
19
+ _yardoc
20
+ doc/
21
+
22
+ # local environment details
23
+ .env
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brilliant Fantastic
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Dropdown
2
+ ========
3
+
4
+ [![Code Climate](https://codeclimate.com/github/brilliantfantastic/dropdown.png)](https://codeclimate.com/github/brilliantfantastic/dropdown)
5
+ [![Build Status](https://travis-ci.org/brilliantfantastic/dropdown.png?branch=master)](https://travis-ci.org/brilliantfantastic/dropdown)
6
+ [![Coverage Status](https://coveralls.io/repos/brilliantfantastic/dropdown/badge.png?branch=master)](https://coveralls.io/r/brilliantfantastic/dropdown?branch=master)
7
+
8
+ Blog engine that parses Markdown files stored in Dropbox for a static blog engine.
9
+
10
+ Installation
11
+ =============
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```sh
16
+ gem 'dropdown'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ ```sh
22
+ $ bundle
23
+ ```
24
+
25
+ Or install it yourself as:
26
+
27
+ ```sh
28
+ $ gem install dropdown
29
+ ```
30
+
31
+ Getting Started with Dropbox storage
32
+ ====================================
33
+
34
+ 1. **Create an application on Dropbox**
35
+
36
+ 1. Sign into Dropbox
37
+ 1. Visit `https://www.dropbox.com/developers/apps/create`
38
+ 1. Choose 'Dropbox API app' for 'What type of app do you want to create?'
39
+ 1. Choose 'Files and datastores' for 'What type of data does your app need to store on Dropbox?'
40
+ 1. Choose 'No -- My app needs access to files already on Dropbox' for 'Can your app be limited to its own, private folder?'
41
+ 1. Choose 'All file types -- My app needs access to a user's full Dropbox' for 'What type of files does your app need access to?'
42
+ 1. Name your application. We suggest something like '<blog name> Dropdown blog'
43
+
44
+ Here is a screenshot of an example of a Dropbox app creation page filled out:
45
+
46
+ ![](https://dl.dropboxusercontent.com/u/987517/oss/Dropdown/README/dropbox-create-app.png)
47
+
48
+ 1. **Enter your Dropbox APP KEY and APP SECRET in environment variables**
49
+
50
+ Once your create a Dropbox application, you will be assigned an App key and an App secret. You will want to put these values in
51
+ environment variables so you can use these in your Dropdown configuration settings. We highly suggest you do not put these values
52
+ straight into your configuration because you do not want them checked into your source control.
53
+
54
+ For development, we recommend using [dotenv](https://github.com/bkeepers/dotenv).
55
+
56
+ 1. For Rails, add this line to your application's `Gemfile`
57
+
58
+ ```ruby
59
+ gem 'dotenv-rails', :groups => [:development, :test]
60
+ ```
61
+
62
+ 1. Create a `.env` file to the root of your project
63
+ 1. Add the `.env` file to your `.gitignore`
64
+ 1. Add the following content to your `.env` file
65
+
66
+ ```
67
+ DROPBOX_APP_KEY=<your app key>
68
+ DROPBOX_APP_SECRET=<your app secret>
69
+ DROPBOX_ACCESS_TOKEN=<your access token>
70
+ ```
71
+
72
+ For production, if you application lives on Heroku, you can run the following:
73
+
74
+ ```sh
75
+ heroku config:set DROPBOX_APP_KEY=<your app key>
76
+ heroku config:set DROPBOX_APP_SECRET=<your app secret>
77
+ heroku config:set DROPBOX_ACCESS_TOKEN=<your access token>
78
+ ```
79
+
80
+ 1. **Update your Dropdown configuration**
81
+
82
+ For Rails, create `config/initializers/dropdown.rb` with the following content:
83
+
84
+ ```ruby
85
+ Dropdown.configure do |c|
86
+ c.dropbox_app_key: ENV['DROPBOX_APP_KEY']
87
+ c.dropdown_app_secret: ENV['DROPBOX_APP_SECRET']
88
+ c.dropdown_access_token: ENV['DROPBOX_ACCESS_TOKEN']
89
+ end
90
+ ```
91
+
92
+ We will be retrieving the `DROPBOX_ACCESS_TOKEN` with the next step.
93
+
94
+ 1. **Run `rake setup:dropbox:access_token`**
95
+
96
+ This will instruct you to go to a Dropbox url to authorize your Dropbox application.
97
+
98
+ Copy the authorization code and enter it the console.
99
+
100
+ Your access token will be displayed and you can copy it to an environment variable: `DROPBOX_ACCESS_TOKEN`.
101
+
102
+ Potential Implementation
103
+ ========================
104
+
105
+ ## Dropbox directory structure
106
+
107
+ <pre>
108
+ - blog-posts
109
+ |-- markdown
110
+ |-- random-post-1.md
111
+ |-- random-post-2.md
112
+ |-- html
113
+ |-- random-post-1.html
114
+ |-- random-post-2.html
115
+ |-- templates
116
+ |-- honeysuckle.handlebars
117
+ |-- .index
118
+ </pre>
119
+
120
+ ## Parsing
121
+
122
+ A rake task will be used to process a directory with Markdown files. The process will read each Markdown file and create an accompanying static file in HTML. This process will use [RedCarpet](https://github.com/vmg/redcarpet) to parse the markdown files and generate HTML files.
123
+
124
+ ```ruby
125
+ # task to process the Markdown directory
126
+ require 'dropdown/processor'
127
+
128
+ task :process [:source, :destination] do |t, args|
129
+ DropDown::Processor.new(args.source, args.destination).process
130
+ end
131
+ ```
132
+
133
+ Additional functionality
134
+
135
+ ```ruby
136
+ DropDown::Processor.new.process(:all) # same as calling DropDown::Processor.new.process
137
+ DropDown::Processor.new.process # uses the source and destination directories specified in the configuration
138
+ ```
139
+
140
+ ### Format of the generated output
141
+
142
+ Each file will have meta data stored as comments in the MarkDown:
143
+
144
+ ```
145
+ Title: Deep Throat Exposed!
146
+ Author: Bob Woodward
147
+ Post: 4/4/1974
148
+
149
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut volutpat molestie condimentum. Vestibulum malesuada,
150
+ lorem sit amet euismod pellentesque, tellus felis varius enim, id tincidunt leo odio aliquet ante. Maecenas metus
151
+ lorem, pretium vitae auctor sed, blandit id quam.
152
+ ```
153
+
154
+ This will generate the following html:
155
+
156
+ ```html
157
+ <!-- Title: Deep Throat Exposed! -->
158
+ <!-- Author: Bob Woodward -->
159
+ <!-- Post: 4/4/1974 -->
160
+ <div class='post'>
161
+ <div class='title'>Deep Throat Exposed!</div>
162
+ <div class='author'>Bob Woodward</div>
163
+ <div class='post'>19740404T....</div>
164
+ <div class='content'>
165
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut volutpat molestie condimentum. Vestibulum malesuada,
166
+ lorem sit amet euismod pellentesque, tellus felis varius enim, id tincidunt leo odio aliquet ante. Maecenas metus
167
+ lorem, pretium vitae auctor sed, blandit id quam.
168
+ </div>
169
+ </div>
170
+ ```
171
+
172
+ This will also create the following row in the .index file:
173
+
174
+ ```
175
+ title: Deep Throat Exposed! author: Bob Woodward post: 19740404T.... slug: deep-throat-exposed checksum: 384749403
176
+ ```
177
+
178
+ ## Retreiving
179
+
180
+ ## Displaying
181
+
182
+ ## Configuration
183
+
184
+ ```ruby
185
+ DropDown.configure do |c|
186
+ c.base_path: 'blog_posts'
187
+ c.source_directory: 'markdown'
188
+ c.destination_directory: 'html'
189
+ c.template: 'honeysuckle'
190
+ c.dropbox_app_key: '<insert dropbox app key>'
191
+ c.dropbox_app_secret: '<insert dropbox app secret key>'
192
+ end
193
+ ```
194
+
@@ -0,0 +1,41 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'dotenv/tasks'
3
+
4
+ task :default => [:test]
5
+
6
+ desc 'Run tests for project'
7
+ task :test do
8
+ sh 'bundle exec rspec'
9
+ end
10
+
11
+ desc 'Process the markdown files in a directory'
12
+ task :process, :source_directory do |t, args|
13
+ require_relative 'lib/dropdown'
14
+ processor = Dropdown::Processor.new
15
+ processor.source = args[:source_directory]
16
+ processor.destination = File.join(processor.source, 'html')
17
+ processor.storage = args[:storage] || :dropbox
18
+ processor.renderer = :markdown_renderer
19
+ processor.process
20
+ end
21
+
22
+ namespace :setup do
23
+ namespace :dropbox do
24
+ desc 'Store a new access token from Dropbox'
25
+ task :access_token => :dotenv do |t, args|
26
+ require 'launchy'
27
+ require_relative 'lib/dropdown'
28
+
29
+ key = args[:key] || ENV['DROPBOX_APP_KEY']
30
+ secret = args[:secret] || ENV['DROPBOX_APP_SECRET']
31
+ session = Dropdown::Dropbox::Session.new key, secret
32
+ url = session.authorize_url
33
+ puts "Opening the following url in your browser: #{url} ..."
34
+ Launchy.open url
35
+ puts "Paste the authorization code below and hit return: "
36
+ code = STDIN.gets.strip
37
+ token = session.access_token(code)
38
+ puts "Your access token is: #{token}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dropdown/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dropdown"
8
+ spec.version = Dropdown::VERSION
9
+
10
+ spec.authors = ["Jamie Wright", "Keith Thompson"]
11
+ spec.email = ["jamie@brilliantfantastic.com", "keith@brilliantfantastic.com"]
12
+
13
+ spec.summary = "Markdown blog engine in Dropbox"
14
+ spec.description = %q{
15
+ A simple blog engine that reads blog posts from a Dropbox source.
16
+ Rake tasks will convert any blog post from Markdown to HTML and
17
+ store them back into Dropbox for the Blog objects to read.
18
+ }
19
+
20
+ spec.homepage = "http://github.com/brilliantfantastic/dropdown"
21
+ spec.license = "MIT"
22
+
23
+ spec.files = `git ls-files`.split($/)
24
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "bundler", "~> 1.3"
28
+ spec.add_dependency "rake"
29
+ spec.add_dependency "dotenv"
30
+ spec.add_dependency "launchy"
31
+ spec.add_dependency "redcarpet"
32
+ spec.add_dependency "nokogiri"
33
+ spec.add_dependency "dropbox-sdk"
34
+ spec.add_development_dependency "coveralls"
35
+ spec.add_development_dependency "rspec"
36
+ spec.add_development_dependency "fakeweb"
37
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'dropdown/version'
2
+ require_relative 'dropdown/dropbox'
3
+ require_relative 'dropdown/processor'
4
+ require_relative 'dropdown/configuration'
5
+ require_relative 'dropdown/output_stores'
6
+ require_relative 'dropdown/readers'
7
+ require_relative 'dropdown/iterators'
8
+ require_relative 'dropdown/parsers/parser'
9
+ require_relative 'dropdown/parsers/metadata_parser'
10
+ require_relative 'dropdown/parsers/excerpt_extractor'
11
+ require_relative 'dropdown/markdown_renderer'
12
+ require_relative 'dropdown/blog'
13
+ require_relative 'dropdown/post'
14
+
15
+ module Dropdown
16
+ def self.configuration
17
+ @configuration ||= Dropdown::Configuration.new
18
+ end
19
+
20
+ def self.configure
21
+ yield configuration if block_given?
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Dropdown
2
+ class Blog
3
+ attr_accessor :name, :source
4
+ attr_reader :reader, :posts
5
+
6
+ def initialize(source=nil, reader=Dropdown::Readers::FileReader.new)
7
+ @source = source
8
+ @reader = reader
9
+ @posts = []
10
+ collect
11
+ end
12
+
13
+ private
14
+
15
+ def collect
16
+ unless @source.nil?
17
+ @reader.find_html_files(@source).each do |html_file|
18
+ @posts << Post.new(html_file, reader)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ module Dropdown
2
+ class Configuration
3
+ attr_accessor :renderer,
4
+ :dropbox_app_key,
5
+ :dropbox_app_secret,
6
+ :dropbox_access_token
7
+
8
+ def initialize
9
+ @renderer = :markdown_renderer
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module Dropdown
2
+ MARKDOWN_EXTENSIONS = %w(.md .markdown)
3
+ HTML_EXTENSIONS = %w(.html)
4
+ end
@@ -0,0 +1 @@
1
+ require_relative 'dropbox/session'
@@ -0,0 +1,18 @@
1
+ require 'dropbox_sdk'
2
+
3
+ module Dropdown
4
+ module Dropbox
5
+ class Session
6
+ attr_reader :authorize_url
7
+
8
+ def initialize(app_key, app_secret)
9
+ @flow = DropboxOAuth2FlowNoRedirect.new app_key, app_secret
10
+ @authorize_url = @flow.start
11
+ end
12
+
13
+ def access_token(authorization_code)
14
+ @flow.finish(authorization_code)[0]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module Dropdown
2
+ class FileTypeError < ArgumentError
3
+ end
4
+ end