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,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