tumblr-themer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.irbrc +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +79 -0
- data/Rakefile +1 -0
- data/bin/tumblr-themer +7 -0
- data/lib/tumblr-themer/api.rb +71 -0
- data/lib/tumblr-themer/chat_line.rb +19 -0
- data/lib/tumblr-themer/cli.rb +56 -0
- data/lib/tumblr-themer/html_snippet.rb +25 -0
- data/lib/tumblr-themer/photoset_photo.rb +20 -0
- data/lib/tumblr-themer/post/audio.rb +35 -0
- data/lib/tumblr-themer/post/chat.rb +6 -0
- data/lib/tumblr-themer/post/link.rb +7 -0
- data/lib/tumblr-themer/post/photo.rb +50 -0
- data/lib/tumblr-themer/post/photoset.rb +7 -0
- data/lib/tumblr-themer/post/quote.rb +10 -0
- data/lib/tumblr-themer/post/text.rb +4 -0
- data/lib/tumblr-themer/post/video.rb +26 -0
- data/lib/tumblr-themer/post.rb +157 -0
- data/lib/tumblr-themer/server.rb +16 -0
- data/lib/tumblr-themer/tag.rb +22 -0
- data/lib/tumblr-themer/tag_helper.rb +79 -0
- data/lib/tumblr-themer/theme.rb +78 -0
- data/lib/tumblr-themer/version.rb +3 -0
- data/lib/tumblr-themer.rb +28 -0
- data/theme_template/config.ru.tt +10 -0
- data/theme_template/index.html.tt +26 -0
- data/theme_template/posts/chat.html.cc +14 -0
- data/theme_template/posts/link.html.tt +8 -0
- data/theme_template/posts/photo.html.tt +6 -0
- data/theme_template/posts/quote.html.tt +8 -0
- data/theme_template/posts/text.html.tt +6 -0
- data/theme_template/posts/video.html.tt +8 -0
- data/theme_template/tumblr-theme.yml.tt +10 -0
- data/tumblr-themer.gemspec +28 -0
- metadata +188 -0
data/.gitignore
ADDED
data/.irbrc
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tumblr-themer
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p392
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Tal Atlas
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Tumblr Themer
|
2
|
+
|
3
|
+
A utility for making tumblr themes easier. Generates a framework for the theme and runs a server to allow you to see your theme with real data while you test.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
You must load this gem manually for now, until it's released to rubygems.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Generation
|
12
|
+
|
13
|
+
Once installed you can generate a base theme in a new folder with
|
14
|
+
|
15
|
+
$ tumblr-themer new theme_name
|
16
|
+
|
17
|
+
or have it place the files in the current directory with:
|
18
|
+
|
19
|
+
$ tumblr-themer new .
|
20
|
+
|
21
|
+
The folder structure generated is as such:
|
22
|
+
|
23
|
+
index.html #=> base layout file
|
24
|
+
config.ru #=> Rack file to allow for use with pow or any other rack app
|
25
|
+
posts/text.html #=> html for text post
|
26
|
+
posts/….html #=> html for each post type
|
27
|
+
tumblr-themer.yml #=> config file
|
28
|
+
|
29
|
+
The utility can inject all the post types into the custom tag `{PostsCode}`
|
30
|
+
so that you can keep your theme more organized. I'm looking to add more custom partial support in the future.
|
31
|
+
|
32
|
+
### Customization
|
33
|
+
|
34
|
+
The `tumblr-themer.yml` file contains configuration information.
|
35
|
+
|
36
|
+
The first thing you need is an api key, found at [tumblr's developer site](http://www.tumblr.com/oauth/apps). It's called the OAuth Consumer Key.
|
37
|
+
|
38
|
+
The second key can be the blog. It's your tumblr base name to get the posts from.
|
39
|
+
|
40
|
+
Optionally you can provide an array of posts to render.
|
41
|
+
|
42
|
+
### Server
|
43
|
+
|
44
|
+
You can run a server by the command
|
45
|
+
|
46
|
+
$ tumblr-themer server
|
47
|
+
|
48
|
+
This starts a web server on localhost:4567.
|
49
|
+
|
50
|
+
You can use the [Pow](http://pow.cx) utility to run the server as well. In fact this method is the recommended way to use this utility.
|
51
|
+
|
52
|
+
### Loading
|
53
|
+
|
54
|
+
To take the html and put it into your tumblr account you can run
|
55
|
+
|
56
|
+
$ tumblr-themer copy
|
57
|
+
|
58
|
+
and it will place the entire theme in your clipboard.
|
59
|
+
|
60
|
+
Alternately you can have it print out the whole theme with:
|
61
|
+
|
62
|
+
$ tumblr-themer stdout
|
63
|
+
|
64
|
+
## Todo
|
65
|
+
|
66
|
+
So many things, starting with:
|
67
|
+
|
68
|
+
* Distinguishig between permalink/listing pages
|
69
|
+
* Testing
|
70
|
+
* More tag support for various post types
|
71
|
+
* Too much to list, please help out with what you want/can
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
1. Fork it
|
76
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
77
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
78
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
79
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/tumblr-themer
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module TumblrThemer::API
|
2
|
+
extend self
|
3
|
+
attr_writer :base_hostname, :api_key
|
4
|
+
|
5
|
+
def base_hostname
|
6
|
+
name = @base_hostname || settings['blog']
|
7
|
+
if name =~ /tumblr\.com/
|
8
|
+
name
|
9
|
+
else
|
10
|
+
"#{name}.tumblr.com"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def settings dirname='.'
|
15
|
+
file = File.expand_path("#{dirname}/tumblr-theme.yml")
|
16
|
+
|
17
|
+
unless File.exist?(file)
|
18
|
+
raise ConfigFileError, "#{file} not found"
|
19
|
+
end
|
20
|
+
|
21
|
+
data = YAML.load_file(file)
|
22
|
+
raise ConfigFileError, "no api_key found in config file" unless data['api_key']
|
23
|
+
data
|
24
|
+
end
|
25
|
+
|
26
|
+
def api_key
|
27
|
+
@api_key ||= settings['api_key']
|
28
|
+
end
|
29
|
+
|
30
|
+
def posts
|
31
|
+
if settings['posts']
|
32
|
+
selected_posts
|
33
|
+
else
|
34
|
+
all_posts['response']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def selected_posts
|
39
|
+
blog = nil
|
40
|
+
posts = []
|
41
|
+
settings['posts'].each do |id|
|
42
|
+
data = all_posts(:id => id)
|
43
|
+
posts << data['response']['posts'].first
|
44
|
+
blog ||= data['response']['blog']
|
45
|
+
end
|
46
|
+
|
47
|
+
{
|
48
|
+
'posts' => posts,
|
49
|
+
'blog' => blog
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def all_posts(params={})
|
54
|
+
url = URL.new("http://api.tumblr.com/v2/blog/#{base_hostname}/posts")
|
55
|
+
url[:api_key] = api_key
|
56
|
+
url[:reblog_info] = true
|
57
|
+
url[:id] = params[:id] if params[:id]
|
58
|
+
json = url.get.json
|
59
|
+
|
60
|
+
status = json['meta']['status']
|
61
|
+
if status == 401
|
62
|
+
raise ConfigFileError, "invalid api_key found in config file"
|
63
|
+
elsif status != 200
|
64
|
+
raise RequestError, json['meta'].inspect
|
65
|
+
end
|
66
|
+
json
|
67
|
+
end
|
68
|
+
|
69
|
+
class ConfigFileError < StandardError; end
|
70
|
+
class RequestError < StandardError; end
|
71
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class TumblrThemer::ChatLine
|
2
|
+
include TumblrThemer::TagHelper
|
3
|
+
attr_reader :html, :data, :line_index
|
4
|
+
|
5
|
+
def initialize html, data, index=0
|
6
|
+
@html = TumblrThemer::HtmlSnippet.new(html.dup) if html
|
7
|
+
@data = data.dup
|
8
|
+
@line_index = index
|
9
|
+
end
|
10
|
+
|
11
|
+
tag('Alt') { line_index%2==0 ? 'odd' : 'even' }
|
12
|
+
|
13
|
+
block('Label') { boolify(data['label']) }
|
14
|
+
tag('Label') { data['label'] }
|
15
|
+
|
16
|
+
tag('UserNumber') { line_index }
|
17
|
+
tag('Name') { data['name'] }
|
18
|
+
tag('Line') { data['phrase'] }
|
19
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'tumblr-themer/server'
|
3
|
+
|
4
|
+
module TumblrThemer
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.expand_path(File.join(File.dirname(__FILE__),'..','..','theme_template'))
|
10
|
+
end
|
11
|
+
|
12
|
+
class_option :'theme-dir', :type => :string, :default => '.', :aliases => %w{-t}
|
13
|
+
|
14
|
+
desc 'new', 'make a new theme in a folder of the name'
|
15
|
+
def new name='.'
|
16
|
+
@name = name
|
17
|
+
|
18
|
+
files = Dir[File.join(self.class.source_root,'**/*.tt')].collect do |f|
|
19
|
+
f.sub(self.class.source_root+'/','')
|
20
|
+
end
|
21
|
+
|
22
|
+
files.each do |source|
|
23
|
+
if name == '.' || name == File.basename(Dir.pwd)
|
24
|
+
dest = ""
|
25
|
+
else
|
26
|
+
dest = "#{name}/"
|
27
|
+
end
|
28
|
+
dest << source.sub(/\.tt$/, '')
|
29
|
+
|
30
|
+
template source, dest
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'copy', 'copy the theme into the clipboard'
|
35
|
+
def copy
|
36
|
+
theme = TumblrThemer::Theme.new(options[:'theme-dir'])
|
37
|
+
|
38
|
+
IO.popen('pbcopy', 'w') { |f| f << theme.body.to_s }
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'stdout', 'print theme to stdout'
|
42
|
+
def stdout
|
43
|
+
theme = TumblrThemer::Theme.new(options[:'theme-dir'])
|
44
|
+
|
45
|
+
puts theme.body
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'server', 'run a server that allows you to play with your theme in the browser'
|
49
|
+
def server
|
50
|
+
TumblrThemer::Server.run!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class TemplateBuilder < Thor
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class TumblrThemer::HtmlSnippet
|
2
|
+
attr_reader :str
|
3
|
+
|
4
|
+
def initialize(str)
|
5
|
+
@str = str.dup
|
6
|
+
end
|
7
|
+
|
8
|
+
def tag key, val
|
9
|
+
str.gsub! "{#{key}}", val.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def block _type, tf=true
|
13
|
+
regex = Regexp.new("{block:#{_type}}(.*?){/block:#{_type}}",Regexp::MULTILINE)
|
14
|
+
|
15
|
+
if tf
|
16
|
+
if block_given?
|
17
|
+
str.gsub!(regex) {yield($1)}
|
18
|
+
else
|
19
|
+
str.gsub!(regex, '\1')
|
20
|
+
end
|
21
|
+
else
|
22
|
+
str.gsub!(regex, '')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class TumblrThemer::PhotosetPhoto
|
2
|
+
include TumblrThemer::TagHelper
|
3
|
+
attr_reader :html, :data
|
4
|
+
|
5
|
+
def initialize html, data, i=0
|
6
|
+
@html = TumblrThemer::HtmlSnippet.new(html.dup) if html
|
7
|
+
@data = data.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def photo_size size
|
11
|
+
data.find {|p| p['width'] == size}||data.first
|
12
|
+
end
|
13
|
+
|
14
|
+
[500,400,250,100].each do |size|
|
15
|
+
tag("PhotoURL-#{size}") { photo_size(size)['url'] }
|
16
|
+
tag("PhotoWidth-#{size}") { photo_size(size)['width'] }
|
17
|
+
tag("PhotoHeight-#{size}") { photo_size(size)['height'] }
|
18
|
+
end
|
19
|
+
tag("PhotoURL-75sq") { photo_size(75)['url'] }
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class TumblrThemer::Post::Audio < TumblrThemer::Post
|
2
|
+
|
3
|
+
def embed_size size
|
4
|
+
data['embed'].gsub(/width=['"](\d+)['"]/,%Q{width="#{size}"})
|
5
|
+
end
|
6
|
+
|
7
|
+
block_tag('Caption')
|
8
|
+
|
9
|
+
block('AudioEmbed', 'embed')
|
10
|
+
[250,400,500,640].each do |size|
|
11
|
+
tag("AudioEmbed-#{size}") { embed_size(size) }
|
12
|
+
end
|
13
|
+
tag("AudioEmbed") { embed_size(500) }
|
14
|
+
|
15
|
+
block('AudioPlayer','player')
|
16
|
+
%w{AudioPlayer AudioPlayerWhite AudioPlayerGrey AudioPlayerBlack}.each do |t|
|
17
|
+
tag(t,'player')
|
18
|
+
end
|
19
|
+
|
20
|
+
block_tag('PlayCount','plays')
|
21
|
+
tag('FormattedPlayCount') { data['plays'].to_s.reverse.gsub(/...(?=.)/,'\&,').reverse }
|
22
|
+
tag('PlayCountWithLabel') do
|
23
|
+
num = data['plays']
|
24
|
+
str = num.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
|
25
|
+
str << (num == 1 ? 'play' : 'plays')
|
26
|
+
end
|
27
|
+
|
28
|
+
block('AlbumArt', 'album_art')
|
29
|
+
tag('AlbumArtURL', 'album_art')
|
30
|
+
|
31
|
+
block_tag('Artist')
|
32
|
+
block_tag('Album')
|
33
|
+
block_tag('TrackName')
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class TumblrThemer::Post::Photo < TumblrThemer::Post
|
2
|
+
def photo
|
3
|
+
data['photos'].first['alt_sizes']
|
4
|
+
end
|
5
|
+
|
6
|
+
def photo_size size
|
7
|
+
photo.find {|p| p['width'] == size}||photo.first
|
8
|
+
end
|
9
|
+
|
10
|
+
def exif
|
11
|
+
data['photos'].first['exif'] || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def exif?
|
15
|
+
boolify(exif)
|
16
|
+
end
|
17
|
+
|
18
|
+
tag('PhotoAlt') { 'alt photo' }
|
19
|
+
|
20
|
+
block('Caption') { boolify(data['caption']) }
|
21
|
+
tag('Caption') { data['caption'] }
|
22
|
+
|
23
|
+
block('LinkURL') { boolify(data['link_url']) }
|
24
|
+
tag('LinkURL') { data['link_url'] }
|
25
|
+
tag('LinkOpenTag') { %Q[<a href="#{data['link_url']}">]}
|
26
|
+
tag('LinkCloseTag') { '</a>' }
|
27
|
+
|
28
|
+
[500,400,250,100].each do |size|
|
29
|
+
tag("PhotoURL-#{size}") do
|
30
|
+
photo_size(size)['url']
|
31
|
+
end
|
32
|
+
tag("PhotoWidth-#{size}") { photo_size(size)['width'] }
|
33
|
+
tag("PhotoHeight-#{size}") { photo_size(size)['height'] }
|
34
|
+
end
|
35
|
+
tag("PhotoURL-75sq") { photo_size(75)['url'] }
|
36
|
+
|
37
|
+
block('HighRes') { false }
|
38
|
+
|
39
|
+
block("Exif") { exif? }
|
40
|
+
block("Camera") { exif? && boolify(exif['Camera'])}
|
41
|
+
tag("Camera") { exif['Camera'] }
|
42
|
+
block("Aperture") { exif? && boolify(exif['Aperture'])}
|
43
|
+
tag("Aperture") { exif['Aperture'] }
|
44
|
+
block("Exposure") { exif? && boolify(exif['Exposure'])}
|
45
|
+
tag("Exposure") { exif['Exposure'] }
|
46
|
+
block("FocalLength") { exif? && boolify(exif['FocalLength'])}
|
47
|
+
tag("FocalLength") { exif['FocalLength'] }
|
48
|
+
block("ISO") { exif? && boolify(exif['ISO'])}
|
49
|
+
tag("ISO") { exif['ISO'] }
|
50
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class TumblrThemer::Post::Photoset < TumblrThemer::Post::Photo
|
2
|
+
[700,500,400,250].each do |size|
|
3
|
+
tag("Photoset-#{size}") { %Q[<img src="http://placekitten.com/#{size}/#{(size*(rand+1)).to_i}" width="#{size}"/>] }
|
4
|
+
end
|
5
|
+
tag("PhotoCount") { data['photos'].size }
|
6
|
+
tag("PostType") { 'photoset' }
|
7
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class TumblrThemer::Post::Video < TumblrThemer::Post
|
2
|
+
def player
|
3
|
+
data['player']||[{}]
|
4
|
+
end
|
5
|
+
|
6
|
+
def video_size size
|
7
|
+
(player.find {|p| p['width'] == size}||player.first)['embed_code']
|
8
|
+
end
|
9
|
+
|
10
|
+
block('Caption') { boolify(data['caption']) }
|
11
|
+
tag('Caption') { data['caption'] }
|
12
|
+
|
13
|
+
[700,500,400,250].each do |size|
|
14
|
+
tag("Video-#{size}") { video_size(size) }
|
15
|
+
tag("VideoEmbed-#{size}") { video_size(size) }
|
16
|
+
end
|
17
|
+
|
18
|
+
tag('PlayCount') { rand(90000) }
|
19
|
+
tag('FormattedPlayCount') { rand(90000).to_s.reverse.gsub(/...(?=.)/,'\&,').reverse }
|
20
|
+
tag('PlayCountWithLabel') do
|
21
|
+
num = rand(90000)
|
22
|
+
str = num.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
|
23
|
+
str << (num == 1 ? 'play' : 'plays')
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
class TumblrThemer::Post
|
2
|
+
include TumblrThemer::TagHelper
|
3
|
+
attr_reader :data, :post_index, :html
|
4
|
+
|
5
|
+
def initialize html, data, index=0
|
6
|
+
@html = TumblrThemer::HtmlSnippet.new(html.dup) if html
|
7
|
+
@data = data.dup
|
8
|
+
@post_index = index
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
self.class.to_s.sub('TumblrThemer::Post::','').downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.render html, data, i=0
|
16
|
+
type = data['type']
|
17
|
+
if type == 'photo'
|
18
|
+
if data['photos'].size > 1
|
19
|
+
klass = TumblrThemer::Post::Photoset
|
20
|
+
else
|
21
|
+
klass = TumblrThemer::Post::Photo
|
22
|
+
end
|
23
|
+
else
|
24
|
+
klass = TumblrThemer::Post.const_get(type.capitalize)
|
25
|
+
end
|
26
|
+
|
27
|
+
klass.new(html,data,i).render
|
28
|
+
# rescue NameError
|
29
|
+
# ''
|
30
|
+
end
|
31
|
+
|
32
|
+
def render
|
33
|
+
return '' unless html
|
34
|
+
|
35
|
+
self.class.blocks.each do |name,blk|
|
36
|
+
html.block(name,instance_exec(self,&blk))
|
37
|
+
end
|
38
|
+
|
39
|
+
self.class.tag_iterators.each do |name,opts|
|
40
|
+
vals = instance_exec(self,&opts[:blk])
|
41
|
+
html.block(name) do |str|
|
42
|
+
strs = []
|
43
|
+
vals.each_with_index { |val,i| strs << opts[:klass].new(str,val,i).render }
|
44
|
+
strs.join("\n")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
puts html.str
|
49
|
+
|
50
|
+
self.class.tags.each do |name, blk|
|
51
|
+
html.tag(name,instance_exec(self,&blk))
|
52
|
+
end
|
53
|
+
|
54
|
+
html.str
|
55
|
+
end
|
56
|
+
|
57
|
+
def reblogged?
|
58
|
+
boolify(data['reblogged_from_id'])
|
59
|
+
end
|
60
|
+
|
61
|
+
def created_at
|
62
|
+
@created_at ||= Time.parse(data['date'])
|
63
|
+
end
|
64
|
+
|
65
|
+
POST_TYPES = %w{
|
66
|
+
text
|
67
|
+
photo
|
68
|
+
panorama
|
69
|
+
photoset
|
70
|
+
quote
|
71
|
+
link
|
72
|
+
chat
|
73
|
+
audio
|
74
|
+
video
|
75
|
+
answer
|
76
|
+
}.each do |_type|
|
77
|
+
block(_type.capitalize) { self.type == _type }
|
78
|
+
end
|
79
|
+
|
80
|
+
tag('PostType') { data['type'] }
|
81
|
+
tag('Permalink') { "/post/#{data['id']}" }
|
82
|
+
tag('ShortURL') { data['short_url'] }
|
83
|
+
tag('PostID') { data['id'] }
|
84
|
+
tag 'TagsAsClasses' do
|
85
|
+
classes = data['tags']||[]
|
86
|
+
classes << 'reblog' if reblogged?
|
87
|
+
classes.join(' ')
|
88
|
+
end
|
89
|
+
|
90
|
+
15.times do |i|
|
91
|
+
block "Post#{i+1}" do
|
92
|
+
post_index == i
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
block('Even') { post_index%2==1 }
|
97
|
+
block('Odd') { post_index%2==0 }
|
98
|
+
|
99
|
+
block('RebloggedFrom') { reblogged? }
|
100
|
+
tag('ReblogParentName') { data['reblogged_from_name'] }
|
101
|
+
tag('ReblogParentTitle') { data['reblogged_from_title'] }
|
102
|
+
tag('ReblogParentURL') { data['reblogged_from_url'] }
|
103
|
+
tag('ReblogRootName') { data['reblogged_root_name'] }
|
104
|
+
tag('ReblogRootTitle') { data['reblogged_root_title'] }
|
105
|
+
tag('ReblogRootURL') { data['reblogged_root_url'] }
|
106
|
+
block('NotReblog') { !reblogged? }
|
107
|
+
|
108
|
+
block('HasTags') { boolify(data['tags']) }
|
109
|
+
for_each('Tags',TumblrThemer::Tag) { data['tags'] }
|
110
|
+
|
111
|
+
block('Date') { true }
|
112
|
+
block('NewDayDate') { post_index%2==1 }
|
113
|
+
block('SameDayDate') { post_index%2==0 }
|
114
|
+
tag('DayOfMonth') { created_at.strftime('%-d') }
|
115
|
+
tag('DayOfMonthWithZero') { created_at.strftime('%d') }
|
116
|
+
tag('DayOfWeek') { created_at.strftime('%A') }
|
117
|
+
tag('ShortDayOfWeek') { created_at.strftime('%a') }
|
118
|
+
tag('DayOfWeekNumber') { created_at.strftime('%u') }
|
119
|
+
# tag('DayOfMonthSuffix') { 'fixme' }
|
120
|
+
tag('DayOfYear') { created_at.yday }
|
121
|
+
tag('WeekOfYear') { created_at.strftime('%U') }
|
122
|
+
tag('Month') { created_at.strftime('%B') }
|
123
|
+
tag('ShortMonth') { created_at.strftime('%b') }
|
124
|
+
tag('MonthNumber') { created_at.strftime('%-m') }
|
125
|
+
tag('MonthNumberWithZero') { created_at.strftime('%m') }
|
126
|
+
tag('Year') { created_at.strftime('%Y') }
|
127
|
+
tag('ShortYear') { created_at.strftime('%y') }
|
128
|
+
tag('AmPm') { created_at.strftime('%P') }
|
129
|
+
tag('CapitalAmPm') { created_at.strftime('%p') }
|
130
|
+
tag('12Hour') { created_at.strftime('%l') }
|
131
|
+
tag('24Hour') { created_at.strftime('%k') }
|
132
|
+
tag('12HourWithZero') { created_at.strftime('%I') }
|
133
|
+
tag('24HourWithZero') { created_at.strftime('%H') }
|
134
|
+
tag('Minutes') { created_at.strftime('%M') }
|
135
|
+
tag('Seconds') { created_at.strftime('%S') }
|
136
|
+
tag('Beats') { created_at.strftime('%L') }
|
137
|
+
tag('Timestamp') { created_at.to_i}
|
138
|
+
# tag('TimeAgo') { 'fixme' }
|
139
|
+
|
140
|
+
block_tag('NoteCount')
|
141
|
+
tag('NoteCountWithLabel') do
|
142
|
+
num = data['note_count'].to_i
|
143
|
+
str = num.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
|
144
|
+
str << (num == 1 ? 'note' : 'notes')
|
145
|
+
end
|
146
|
+
|
147
|
+
block('ContentSource', 'source_url')
|
148
|
+
tag('SourceURL')
|
149
|
+
tag('SourceTitle')
|
150
|
+
tag('BlackLogoURL') { 'http://assets.tumblr.com/images/source_logos/fastcompany_7f8b98.png?1092' }
|
151
|
+
tag('LogoWidth') { 74 }
|
152
|
+
tag('LogoHeight') { 11 }
|
153
|
+
|
154
|
+
def source_logo; @source_logo ||= rand(2); end
|
155
|
+
block('SourceLogo') { source_logo == 0 }
|
156
|
+
block('NoSourceLogo') { source_logo == 1 }
|
157
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
class TumblrThemer::Server < Sinatra::Base
|
4
|
+
get '/' do
|
5
|
+
theme = TumblrThemer::Theme.new('.')
|
6
|
+
|
7
|
+
theme.render
|
8
|
+
end
|
9
|
+
|
10
|
+
get '/post/:id' do
|
11
|
+
theme = TumblrThemer::Theme.new('.')
|
12
|
+
end
|
13
|
+
|
14
|
+
# start the server if ruby file executed directly
|
15
|
+
run! if app_file == $0
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TumblrThemer::Tag
|
2
|
+
include TumblrThemer::TagHelper
|
3
|
+
attr_reader :html, :data
|
4
|
+
|
5
|
+
def initialize html, data, index=0
|
6
|
+
@html = TumblrThemer::HtmlSnippet.new(html.dup) if html
|
7
|
+
@data = data.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
self.class.tags.each do |name, blk|
|
12
|
+
html.tag(name,instance_exec(self,&blk))
|
13
|
+
end
|
14
|
+
|
15
|
+
html.str
|
16
|
+
end
|
17
|
+
|
18
|
+
tag('Tag') { data }
|
19
|
+
tag('URLSafeTag') { CGI.escape(data) }
|
20
|
+
tag('TagURL') { '#' }
|
21
|
+
tag('TagURLChrono') { '#' }
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module TumblrThemer::TagHelper
|
2
|
+
module InstanceMethods
|
3
|
+
def tag name
|
4
|
+
blk = self.class.tags[name]
|
5
|
+
|
6
|
+
instance_exec(self,&blk)
|
7
|
+
end
|
8
|
+
|
9
|
+
def block name
|
10
|
+
instance_exec(self,&blk)
|
11
|
+
end
|
12
|
+
|
13
|
+
def boolify val
|
14
|
+
if !val
|
15
|
+
false
|
16
|
+
elsif val.respond_to?(:empty?) && val.empty?
|
17
|
+
false
|
18
|
+
else
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# File activesupport/lib/active_support/inflector/methods.rb, line 77
|
24
|
+
def underscore(camel_cased_word)
|
25
|
+
word = camel_cased_word.to_s.dup
|
26
|
+
word.gsub!(/::/, '/')
|
27
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
28
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
29
|
+
word.tr!("-", "_")
|
30
|
+
word.downcase!
|
31
|
+
word
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
def tags
|
38
|
+
@tags ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def tag name, data_name=nil, &blk
|
42
|
+
blk ||= Proc.new { data[data_name||underscore(name)] }
|
43
|
+
tags[name] = blk
|
44
|
+
end
|
45
|
+
|
46
|
+
def for_each name, klass, &blk
|
47
|
+
tag_iterators[name] = {:klass => klass, :blk => blk}
|
48
|
+
end
|
49
|
+
|
50
|
+
def tag_iterators
|
51
|
+
@tag_iterators ||= {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def blocks
|
55
|
+
@blocks ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def block name, data_name=nil, &blk
|
59
|
+
blk ||= Proc.new { boolify(data[data_name||underscore(name)]) }
|
60
|
+
blocks[name] = blk
|
61
|
+
end
|
62
|
+
|
63
|
+
def block_tag name, data_name=nil
|
64
|
+
block(name,data_name)
|
65
|
+
tag(name,data_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def inherited subklass
|
69
|
+
subklass.instance_variable_set(:@tags,@tags.dup)
|
70
|
+
subklass.instance_variable_set(:@blocks,@blocks.dup)
|
71
|
+
subklass.instance_variable_set(:@tag_iterators,@tag_iterators.dup)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.included subklass
|
76
|
+
subklass.send :include, InstanceMethods
|
77
|
+
subklass.extend ClassMethods
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class TumblrThemer::Theme
|
2
|
+
include TumblrThemer::TagHelper
|
3
|
+
attr_reader :body
|
4
|
+
|
5
|
+
def initialize dirname
|
6
|
+
base = File.expand_path(dirname)
|
7
|
+
|
8
|
+
@body = File.read(File.join(base,'index.html'))
|
9
|
+
@posts = {}
|
10
|
+
Dir[File.join(base,'posts/*.html')].each do |f|
|
11
|
+
basename = File.basename(f).sub(/\.html$/,'').gsub(/[_-]/,' ')
|
12
|
+
html = File.read(f)
|
13
|
+
@posts[basename] = html
|
14
|
+
end
|
15
|
+
|
16
|
+
posts_html = @posts.collect do |basename, html|
|
17
|
+
str = "{block:#{basename.capitalize}}"
|
18
|
+
str << html
|
19
|
+
str << "{/block:#{basename.capitalize}}"
|
20
|
+
end
|
21
|
+
|
22
|
+
@body.gsub!("{PostsCode}",posts_html.join("\n"))
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_data
|
26
|
+
return @post_data if defined?(@post_data)
|
27
|
+
data = TumblrThemer::API.posts
|
28
|
+
@blog_data = data['blog']
|
29
|
+
@post_data = data['posts']
|
30
|
+
end
|
31
|
+
|
32
|
+
def post_data
|
33
|
+
@post_data || (get_data && @post_data)
|
34
|
+
end
|
35
|
+
|
36
|
+
def blog_data
|
37
|
+
@blog_data || (get_data && @blog_data)
|
38
|
+
end
|
39
|
+
|
40
|
+
def render
|
41
|
+
html = TumblrThemer::HtmlSnippet.new(@body)
|
42
|
+
|
43
|
+
self.class.tag_iterators.each do |name, opts|
|
44
|
+
vals = instance_exec(self,&opts[:blk])
|
45
|
+
html.block(name) do |str|
|
46
|
+
vals.collect.with_index do |val,i|
|
47
|
+
opts[:klass].render(str,val,i)
|
48
|
+
end.join("\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
self.class.blocks.each do |name,blk|
|
53
|
+
html.block(name,instance_exec(self,&blk))
|
54
|
+
end
|
55
|
+
|
56
|
+
self.class.tags.each do |name, blk|
|
57
|
+
html.tag(name,instance_exec(self,&blk))
|
58
|
+
end
|
59
|
+
|
60
|
+
html.str
|
61
|
+
end
|
62
|
+
|
63
|
+
for_each('Posts',TumblrThemer::Post) { post_data }
|
64
|
+
|
65
|
+
tag('Title') { blog_data['title'] }
|
66
|
+
tag('Description') { blog_data['description'] }
|
67
|
+
tag('CopyrightYears') {'2007-2013'}
|
68
|
+
tag('CustomCSS') {''}
|
69
|
+
|
70
|
+
# block('IndexPage') { true }
|
71
|
+
# block('PermalinkPage') { false }
|
72
|
+
# block('PostTitle') { false }
|
73
|
+
# tag('PostTitle') {''}
|
74
|
+
# block('PostSummary') { false }
|
75
|
+
# tag('PostSummary') {''}
|
76
|
+
|
77
|
+
block('Date') { false }
|
78
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'url'
|
3
|
+
require 'json'
|
4
|
+
require "yaml"
|
5
|
+
require 'cgi'
|
6
|
+
|
7
|
+
require "tumblr-themer/version"
|
8
|
+
|
9
|
+
module TumblrThemer
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'tumblr-themer/api'
|
14
|
+
require 'tumblr-themer/tag_helper'
|
15
|
+
require 'tumblr-themer/html_snippet'
|
16
|
+
require 'tumblr-themer/tag'
|
17
|
+
require 'tumblr-themer/photoset_photo'
|
18
|
+
require 'tumblr-themer/chat_line'
|
19
|
+
require 'tumblr-themer/post'
|
20
|
+
require 'tumblr-themer/theme'
|
21
|
+
require 'tumblr-themer/post/audio'
|
22
|
+
require 'tumblr-themer/post/quote'
|
23
|
+
require 'tumblr-themer/post/text'
|
24
|
+
require 'tumblr-themer/post/photo'
|
25
|
+
require 'tumblr-themer/post/photoset'
|
26
|
+
require 'tumblr-themer/post/link'
|
27
|
+
require 'tumblr-themer/post/video'
|
28
|
+
require 'tumblr-themer/post/chat'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= @name %> Tumblr Theme</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<h1>Look for me in index.html</h1>
|
8
|
+
<div class="posts">
|
9
|
+
{block:Posts}
|
10
|
+
<article class="post {PostType}" id="post{PostID}">
|
11
|
+
{PostsCode}
|
12
|
+
|
13
|
+
{block:HasTags}
|
14
|
+
<section class="tags">
|
15
|
+
{block:Tags}
|
16
|
+
<a href="{TagURL}" class="tag">#{Tag}</a>
|
17
|
+
{/block:Tags}
|
18
|
+
|
19
|
+
</section>
|
20
|
+
{/block:HasTags}
|
21
|
+
</article>
|
22
|
+
{/block:Posts}
|
23
|
+
</div>
|
24
|
+
</body>
|
25
|
+
</html>
|
26
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{block:Title}
|
2
|
+
<h1>{Title}</h1>
|
3
|
+
{/block:Title}
|
4
|
+
<section class="body">
|
5
|
+
{block:Lines}
|
6
|
+
<div class="line {Alt}">
|
7
|
+
{block:Label}
|
8
|
+
<label>{Label}</label>
|
9
|
+
{/block:Label}
|
10
|
+
<span class="name user-{UserNumber}">{Name}</span>
|
11
|
+
<span class="phrase">{Line}</span>
|
12
|
+
</div>
|
13
|
+
{/block:Lines}
|
14
|
+
</section>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tumblr-themer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tumblr-themer"
|
8
|
+
spec.version = TumblrThemer::VERSION
|
9
|
+
spec.authors = ["Tal Atlas"]
|
10
|
+
spec.email = ["me@tal.by"]
|
11
|
+
spec.description = %q{A tool for building tumblr themes}
|
12
|
+
spec.summary = %q{A tool for building tumblr themes}
|
13
|
+
spec.homepage = "https://github.com/tal/tumblr-themer"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "url"
|
22
|
+
spec.add_dependency "sinatra"
|
23
|
+
spec.add_dependency "json"
|
24
|
+
spec.add_dependency "thor"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tumblr-themer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tal Atlas
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: url
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sinatra
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: thor
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.3'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.3'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rake
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: A tool for building tumblr themes
|
111
|
+
email:
|
112
|
+
- me@tal.by
|
113
|
+
executables:
|
114
|
+
- tumblr-themer
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .irbrc
|
120
|
+
- .ruby-gemset
|
121
|
+
- .ruby-version
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- bin/tumblr-themer
|
127
|
+
- lib/tumblr-themer.rb
|
128
|
+
- lib/tumblr-themer/api.rb
|
129
|
+
- lib/tumblr-themer/chat_line.rb
|
130
|
+
- lib/tumblr-themer/cli.rb
|
131
|
+
- lib/tumblr-themer/html_snippet.rb
|
132
|
+
- lib/tumblr-themer/photoset_photo.rb
|
133
|
+
- lib/tumblr-themer/post.rb
|
134
|
+
- lib/tumblr-themer/post/audio.rb
|
135
|
+
- lib/tumblr-themer/post/chat.rb
|
136
|
+
- lib/tumblr-themer/post/link.rb
|
137
|
+
- lib/tumblr-themer/post/photo.rb
|
138
|
+
- lib/tumblr-themer/post/photoset.rb
|
139
|
+
- lib/tumblr-themer/post/quote.rb
|
140
|
+
- lib/tumblr-themer/post/text.rb
|
141
|
+
- lib/tumblr-themer/post/video.rb
|
142
|
+
- lib/tumblr-themer/server.rb
|
143
|
+
- lib/tumblr-themer/tag.rb
|
144
|
+
- lib/tumblr-themer/tag_helper.rb
|
145
|
+
- lib/tumblr-themer/theme.rb
|
146
|
+
- lib/tumblr-themer/version.rb
|
147
|
+
- theme_template/config.ru.tt
|
148
|
+
- theme_template/index.html.tt
|
149
|
+
- theme_template/posts/chat.html.cc
|
150
|
+
- theme_template/posts/link.html.tt
|
151
|
+
- theme_template/posts/photo.html.tt
|
152
|
+
- theme_template/posts/quote.html.tt
|
153
|
+
- theme_template/posts/text.html.tt
|
154
|
+
- theme_template/posts/video.html.tt
|
155
|
+
- theme_template/tumblr-theme.yml.tt
|
156
|
+
- tumblr-themer.gemspec
|
157
|
+
homepage: https://github.com/tal/tumblr-themer
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
post_install_message:
|
161
|
+
rdoc_options: []
|
162
|
+
require_paths:
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
none: false
|
166
|
+
requirements:
|
167
|
+
- - ! '>='
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
segments:
|
171
|
+
- 0
|
172
|
+
hash: -3075578209271866441
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
none: false
|
175
|
+
requirements:
|
176
|
+
- - ! '>='
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
segments:
|
180
|
+
- 0
|
181
|
+
hash: -3075578209271866441
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project:
|
184
|
+
rubygems_version: 1.8.25
|
185
|
+
signing_key:
|
186
|
+
specification_version: 3
|
187
|
+
summary: A tool for building tumblr themes
|
188
|
+
test_files: []
|