tumblargh 0.1.0

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 (59) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +52 -0
  5. data/LICENSE +20 -0
  6. data/README.md +84 -0
  7. data/Rakefile +43 -0
  8. data/VERSION +1 -0
  9. data/examples/confg.ru +18 -0
  10. data/examples/middleman_config.rb +7 -0
  11. data/lib/middleman/features/tumblargh.rb +41 -0
  12. data/lib/rack/tumblargh.rb +51 -0
  13. data/lib/tumblargh.rb +60 -0
  14. data/lib/tumblargh/api.rb +60 -0
  15. data/lib/tumblargh/grammar.rb +560 -0
  16. data/lib/tumblargh/grammar.treetop +42 -0
  17. data/lib/tumblargh/node.rb +14 -0
  18. data/lib/tumblargh/node/base.rb +21 -0
  19. data/lib/tumblargh/node/block.rb +31 -0
  20. data/lib/tumblargh/node/block_end.rb +9 -0
  21. data/lib/tumblargh/node/block_start.rb +22 -0
  22. data/lib/tumblargh/node/literal.rb +9 -0
  23. data/lib/tumblargh/node/root.rb +17 -0
  24. data/lib/tumblargh/node/tag.rb +33 -0
  25. data/lib/tumblargh/parser.rb +96 -0
  26. data/lib/tumblargh/renderer.rb +316 -0
  27. data/lib/tumblargh/renderer/base.rb +64 -0
  28. data/lib/tumblargh/renderer/blocks/answer.rb +22 -0
  29. data/lib/tumblargh/renderer/blocks/audio.rb +70 -0
  30. data/lib/tumblargh/renderer/blocks/base.rb +35 -0
  31. data/lib/tumblargh/renderer/blocks/dates.rb +62 -0
  32. data/lib/tumblargh/renderer/blocks/navigation.rb +65 -0
  33. data/lib/tumblargh/renderer/blocks/notes.rb +68 -0
  34. data/lib/tumblargh/renderer/blocks/posts.rb +50 -0
  35. data/lib/tumblargh/renderer/blocks/reblogs.rb +50 -0
  36. data/lib/tumblargh/renderer/blocks/tags.rb +37 -0
  37. data/lib/tumblargh/renderer/document.rb +70 -0
  38. data/lib/tumblargh/renderer/literal.rb +9 -0
  39. data/lib/tumblargh/renderer/tag.rb +37 -0
  40. data/lib/tumblargh/resource.rb +12 -0
  41. data/lib/tumblargh/resource/base.rb +39 -0
  42. data/lib/tumblargh/resource/blog.rb +49 -0
  43. data/lib/tumblargh/resource/note.rb +8 -0
  44. data/lib/tumblargh/resource/post.rb +63 -0
  45. data/lib/tumblargh/resource/tag.rb +8 -0
  46. data/lib/tumblargh/resource/user.rb +8 -0
  47. data/spec/api_spec.rb +1 -0
  48. data/spec/fixtures/data/staff.tumblr.com-2012-05-06/posts.json +1203 -0
  49. data/spec/fixtures/themes/fluid.html +1138 -0
  50. data/spec/fixtures/themes/solstice.html +392 -0
  51. data/spec/parser_spec.rb +159 -0
  52. data/spec/renderer/blocks/posts_spec.rb +17 -0
  53. data/spec/renderer/document_spec.rb +57 -0
  54. data/spec/resource/post_spec.rb +38 -0
  55. data/spec/resource_spec.rb +23 -0
  56. data/spec/spec_helper.rb +24 -0
  57. data/spec/tumblargh_spec.rb +50 -0
  58. data/tumblargh.gemspec +120 -0
  59. metadata +237 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ coverage/
2
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'activesupport', '>= 3.1'
4
+ gem 'treetop'
5
+ gem 'nokogiri'
6
+ gem 'api_cache'
7
+
8
+
9
+ group :development do
10
+ gem 'autotest-standalone'
11
+ gem 'jeweler'
12
+ gem 'rake'
13
+ gem 'rspec'
14
+ gem 'simplecov'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.2)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ api_cache (0.2.3)
8
+ autotest-standalone (4.5.9)
9
+ diff-lcs (1.1.3)
10
+ git (1.2.5)
11
+ i18n (0.6.0)
12
+ jeweler (1.8.3)
13
+ bundler (~> 1.0)
14
+ git (>= 1.2.5)
15
+ rake
16
+ rdoc
17
+ json (1.6.6)
18
+ multi_json (1.1.0)
19
+ nokogiri (1.5.2)
20
+ polyglot (0.3.3)
21
+ rake (0.9.2.2)
22
+ rdoc (3.12)
23
+ json (~> 1.4)
24
+ rspec (2.8.0)
25
+ rspec-core (~> 2.8.0)
26
+ rspec-expectations (~> 2.8.0)
27
+ rspec-mocks (~> 2.8.0)
28
+ rspec-core (2.8.0)
29
+ rspec-expectations (2.8.0)
30
+ diff-lcs (~> 1.1.2)
31
+ rspec-mocks (2.8.0)
32
+ simplecov (0.6.1)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.5.3)
35
+ simplecov-html (0.5.3)
36
+ treetop (1.4.10)
37
+ polyglot
38
+ polyglot (>= 0.3.1)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ activesupport (>= 3.1)
45
+ api_cache
46
+ autotest-standalone
47
+ jeweler
48
+ nokogiri
49
+ rake
50
+ rspec
51
+ simplecov
52
+ treetop
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jason Webster, MetaLab Design Ltd.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Tumblargh
2
+ ## Groan-less Tumblr theme development
3
+
4
+ ### What is this thing, and why should I care?
5
+
6
+ If you've ever had to build a Tumblr theme, you've probably cried out in pain
7
+ while tweaking locally, copying, pasting into the theme editor, saving, switching
8
+ tabs and finally refreshing and waiting for your tesing blog to reload.
9
+
10
+ Tumblargh aims to reduce suffering involved with building a theme by offering
11
+ a way to fully develop, lint and test Tumblr themes locally, with real posts
12
+ from any existing Tumblog.
13
+
14
+ ### Getting Started
15
+
16
+ You'll need to get an OAuth consumer key for the Tumblr v2 API to use remote data
17
+ with Tumblargh. Registration is simple enough, just go to http://www.tumblr.com/oauth/apps
18
+ and fill out the form. Any time Tumblargh asks for your API key, it'll be the
19
+ OAuth Consumer key provided there.
20
+
21
+ #### Middleman
22
+
23
+ The recommended way to use tumblargh is in conjuction with
24
+ [Middleman](http://middlemanapp.com/).
25
+
26
+ > Middleman is a static site generator based on Sinatra. Providing dozens of
27
+ templating languages (Haml, Sass, Compass, Slim, CoffeeScript, and more).
28
+
29
+ Tumblargh includes a simple Middleman extension that turns any Middleman project
30
+ into a local Tumblr theme building machine.
31
+
32
+ Tumblargh will automatically parse any html files served by Middleman, and
33
+ populate them with content from the Tumblr of your choosing. It will not
34
+ parse any HTML during Middleman's build process. The output of`middleman build`
35
+ is ready for use on your blog, or submission to the Tumblr theme store.
36
+
37
+ To get up an running with Middleman, first create a new Middleman project:
38
+
39
+ ```
40
+ $ middleman init MY_PROJECT_NAME
41
+ ```
42
+
43
+ If one does not already exist, create a Gemfile and add the following as needed:
44
+
45
+ ```ruby
46
+ source "http://rubygems.org"
47
+
48
+ gem 'middleman'
49
+ gem 'tumblargh', :git => 'git://github.com/jasonwebster/tumblargh.git'
50
+ ```
51
+
52
+ Note that there has not yet been an official release of tumblargh to RubyGems,
53
+ so currently, specifying the gem via git is necessary.
54
+
55
+ Run `bundle install`.
56
+
57
+ The bare minimum setup in your Middleman config.rb is:
58
+
59
+ ```ruby
60
+ require 'tumblargh'
61
+ require 'middleman/features/tumblargh'
62
+
63
+ activate :tumblargh
64
+
65
+ set_tumblr_api_key 'API KEY' # This is your OAuth consumer key
66
+ set_tumblr_blog 'staff.tumblr.com'
67
+ ```
68
+
69
+ It is highly recommended to run the Middleman server via `bundle exec`.
70
+
71
+ #### Rack
72
+
73
+ See `examples/config.ru` for a minimal Rack setup, ready to go with `rackup` or
74
+ your Ruby server of choice.
75
+
76
+ ### Known issues & planned features
77
+
78
+ - Source attribution `{block:ContentSource}`
79
+ - Your likes `{block:Likes}`
80
+ - Twitter integration `{block:Twitter}`
81
+ - Custom page support
82
+
83
+
84
+
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Default: run specs.'
7
+ task :default => :spec
8
+
9
+ desc "Run specs"
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
12
+ # Put spec opts in a file named .rspec in root
13
+ end
14
+
15
+ desc "Generate code coverage"
16
+ RSpec::Core::RakeTask.new(:coverage) do |t|
17
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
18
+ end
19
+
20
+
21
+ desc "Open an irb session preloaded with this library"
22
+ task :console do
23
+ sh "irb -rubygems -I lib -r tumblargh.rb"
24
+ end
25
+
26
+
27
+ require 'jeweler'
28
+ Jeweler::Tasks.new do |s|
29
+ s.name = 'tumblargh'
30
+ s.summary = 'Groan-less Tumblr theme development.'
31
+ s.description = `cat README.md`
32
+ s.authors = ['Jason Webster']
33
+ s.email = 'jason@metalabdesign.com'
34
+ s.homepage = 'http://github.com/jasonwebster/tumblargh'
35
+
36
+ s.files = `git ls-files`.split("\n")
37
+ s.require_path = 'lib'
38
+ end
39
+
40
+ Jeweler::RubygemsDotOrgTasks.new
41
+
42
+
43
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/examples/confg.ru ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ require 'tumblargh'
6
+
7
+ Tumblargh::API::set_api_key 'YOUR_TUMBLR_API_KEY'
8
+
9
+ map "/" do
10
+
11
+ app = proc do |env|
12
+ html = Tumblargh::render_file('my_theme.html', 'willw.tumblr.com')
13
+
14
+ [200, { "Content-Type" => "text/html" }, html.lines]
15
+ end
16
+
17
+ run app
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'tumblargh'
2
+ require 'middleman/features/tumblargh'
3
+
4
+
5
+ activate :tumblargh
6
+ set_tumblr_api_key 'API KEY'
7
+ set_tumlbr_blog 'staff.tumblr.com'
@@ -0,0 +1,41 @@
1
+ require 'rack/tumblargh'
2
+
3
+ module Middleman::Features::Tumblargh
4
+
5
+ class << self
6
+
7
+ def registered(app)
8
+ options = {}
9
+ app.set(:tumblr_options, options)
10
+ app.extend(ClassMethods)
11
+
12
+ unless app.build?
13
+ app.use(Rack::Tumblargh, options)
14
+
15
+ ['/tweets.js', %r{/api.*}].each do |route|
16
+ app.get route do
17
+ redirect "http://#{app.tumblr_options[:blog]}#{request.path}?#{request.query_string}"
18
+ end
19
+ end
20
+
21
+ app.page '/post/:id*', :proxy => '/index.html'
22
+ end
23
+ end
24
+
25
+ alias :included :registered
26
+
27
+ module ClassMethods
28
+ def tumblr_api_key=(key)
29
+ Tumblargh::API::set_api_key(key)
30
+ end
31
+
32
+ def tumblr_blog=(blog=nil)
33
+ tumblr_options[:blog] = blog
34
+ end
35
+
36
+ alias_method :set_tumblr_api_key, :tumblr_api_key=
37
+ alias_method :set_tumblr_blog, :tumblr_blog=
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ module Rack
2
+ class Tumblargh
3
+ Tumblargh = ::Tumblargh
4
+
5
+ def initialize(app, options={})
6
+ @app = app
7
+ @options = options
8
+ @options[:blog] = 'staff.tumblr.com' if @options[:blog].nil?
9
+ end
10
+
11
+ attr_reader :options
12
+
13
+ def call(env)
14
+ status, headers, response = @app.call(env)
15
+
16
+ if should_parse?(status, headers)
17
+
18
+ content = response.respond_to?(:body) ? response.body : response
19
+ render_opts = { :permalink => permalink?(env['PATH_INFO']) }
20
+
21
+ headers.delete('Content-Length')
22
+ response = Rack::Response.new(
23
+ render(content, render_opts),
24
+ status,
25
+ headers
26
+ )
27
+ response.finish
28
+ response.to_a
29
+ else
30
+ [status, headers, response]
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def permalink?(path)
37
+ !! path.match(/^\/post\/\d+/)
38
+ end
39
+
40
+ def should_parse?(status, headers)
41
+ status == 200 &&
42
+ headers["Content-Type"] &&
43
+ headers["Content-Type"].include?("text/html")
44
+ end
45
+
46
+ def render(content, opts)
47
+ Tumblargh::render_html(content.first, options[:blog], opts)
48
+ end
49
+
50
+ end
51
+ end
data/lib/tumblargh.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+ require 'active_support/core_ext/string/conversions'
4
+ require 'active_support/core_ext/time/conversions'
5
+ require 'active_support/inflector'
6
+
7
+ module Tumblargh
8
+
9
+ autoload :API, 'tumblargh/api'
10
+ autoload :Node, 'tumblargh/node'
11
+ autoload :Parser, 'tumblargh/parser'
12
+ autoload :Renderer, 'tumblargh/renderer'
13
+ autoload :Resource, 'tumblargh/resource'
14
+
15
+ class << self
16
+
17
+ attr_accessor :config
18
+
19
+ def render_file(file, blog, options={})
20
+ render(:file, file, blog, options)
21
+ end
22
+
23
+ def render_html(string, blog, options={})
24
+ render(:html, string, blog, options)
25
+ end
26
+
27
+ private
28
+
29
+ def render(setter, theme, blog, options)
30
+ parser = Parser.new
31
+ parser.send("#{setter}=", theme)
32
+
33
+ blog = create_blog blog
34
+
35
+ options = parser.options.merge(options)
36
+
37
+ Renderer::Document.new(parser.tree, blog, options).render
38
+ end
39
+
40
+ def create_blog(blog)
41
+ if blog.is_a? Resource::Blog
42
+ blog
43
+ elsif blog.is_a? Hash
44
+ create_blog_from_hash blog
45
+ elsif File.exists? blog
46
+ json = ActiveSupport::JSON.decode(open(blog).read)
47
+ create_blog_from_hash json
48
+ else
49
+ Resource::Blog.new(blog)
50
+ end
51
+ end
52
+
53
+ def create_blog_from_hash(hash)
54
+ hash = hash["response"] if hash.key? "response"
55
+ Resource::Blog.new("#{hash["blog"]["name"]}.tumblr.com", hash)
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,60 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+ require 'active_support/core_ext/object/to_query'
4
+ require 'active_support/json'
5
+
6
+ require 'api_cache'
7
+ require 'open-uri'
8
+
9
+ module Tumblargh
10
+ module API
11
+
12
+ API_ROOT = 'http://api.tumblr.com/v2/blog/'
13
+
14
+ @enabled = true
15
+
16
+ class << self
17
+
18
+ attr_accessor :api_key
19
+ alias_method :set_api_key, :api_key=
20
+
21
+ def fetch(path, query={})
22
+ raise "API is disabled" unless enabled?
23
+
24
+ query = query.merge(:api_key => api_key).to_query
25
+ url = "#{API_ROOT}#{path}?#{query}"
26
+ resp = APICache.get(url) { open(url).read }
27
+ ActiveSupport::JSON.decode(resp)['response']
28
+ end
29
+
30
+ def blog(domain)
31
+ fetch("#{domain}/info")['blog']
32
+ end
33
+
34
+ def posts(domain, query={})
35
+ fetch("#{domain}/posts")['posts']
36
+ end
37
+
38
+ def notes(domain, query)
39
+ query.merge!(:notes_info => 'true')
40
+ fetch("#{domain}/posts", query)['posts'][0]['notes']
41
+ end
42
+
43
+
44
+ def enable!
45
+ @enabled = true
46
+ end
47
+
48
+ def disable!
49
+ @enabled = false
50
+ end
51
+
52
+ def enabled?
53
+ @enabled
54
+ end
55
+
56
+ end
57
+
58
+
59
+ end
60
+ end