yuzu 0.2.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.yardopts +7 -0
- data/ChangeLog.md +8 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +30 -0
- data/LICENSE.txt +20 -0
- data/README.md +52 -0
- data/Rakefile +62 -0
- data/bin/yuzu +17 -0
- data/docs/About.md +19 -0
- data/docs/GettingStarted.md +48 -0
- data/docs/Reference.md +97 -0
- data/lib/helpers/object.rb +19 -0
- data/lib/helpers/path.rb +296 -0
- data/lib/helpers/string.rb +35 -0
- data/lib/helpers/system_checks.rb +10 -0
- data/lib/helpers/url.rb +64 -0
- data/lib/html/base.rb +187 -0
- data/lib/uploader/base.rb +59 -0
- data/lib/uploader/config.rb +19 -0
- data/lib/uploader/filesystem_service.rb +72 -0
- data/lib/uploader/ftp_service.rb +90 -0
- data/lib/uploader/s3_service.rb +135 -0
- data/lib/uploader/service.rb +57 -0
- data/lib/uploader/suppressor.rb +25 -0
- data/lib/yuzu.rb +6 -0
- data/lib/yuzu/argparse.rb +60 -0
- data/lib/yuzu/command.rb +104 -0
- data/lib/yuzu/commands/base.rb +150 -0
- data/lib/yuzu/commands/create.rb +68 -0
- data/lib/yuzu/commands/generate.rb +95 -0
- data/lib/yuzu/commands/help.rb +20 -0
- data/lib/yuzu/commands/preview.rb +58 -0
- data/lib/yuzu/commands/publish.rb +43 -0
- data/lib/yuzu/commands/stage.rb +62 -0
- data/lib/yuzu/commands/watch.rb +70 -0
- data/lib/yuzu/content/blog_post.rb +45 -0
- data/lib/yuzu/content/sample_project.rb +130 -0
- data/lib/yuzu/core/config.rb +154 -0
- data/lib/yuzu/core/layout.rb +85 -0
- data/lib/yuzu/core/paginated_file.rb +69 -0
- data/lib/yuzu/core/registrar.rb +32 -0
- data/lib/yuzu/core/siteroot.rb +57 -0
- data/lib/yuzu/core/template.rb +158 -0
- data/lib/yuzu/core/updater.rb +123 -0
- data/lib/yuzu/core/visitor.rb +44 -0
- data/lib/yuzu/core/website_base.rb +150 -0
- data/lib/yuzu/core/website_file.rb +270 -0
- data/lib/yuzu/core/website_folder.rb +176 -0
- data/lib/yuzu/filters/base.rb +86 -0
- data/lib/yuzu/filters/catalog.rb +248 -0
- data/lib/yuzu/filters/categories.rb +58 -0
- data/lib/yuzu/filters/currentpath.rb +35 -0
- data/lib/yuzu/filters/description.rb +16 -0
- data/lib/yuzu/filters/extension.rb +16 -0
- data/lib/yuzu/filters/images.rb +32 -0
- data/lib/yuzu/filters/linkroot.rb +35 -0
- data/lib/yuzu/filters/post_date.rb +45 -0
- data/lib/yuzu/filters/post_title.rb +66 -0
- data/lib/yuzu/filters/post_title_removed.rb +28 -0
- data/lib/yuzu/filters/sidebar.rb +26 -0
- data/lib/yuzu/filters/template.rb +16 -0
- data/lib/yuzu/generators/base.rb +44 -0
- data/lib/yuzu/generators/category_folders.rb +91 -0
- data/lib/yuzu/generators/index.rb +108 -0
- data/lib/yuzu/generators/paginate.rb +136 -0
- data/lib/yuzu/postprocessors/all_categories.rb +48 -0
- data/lib/yuzu/postprocessors/base.rb +34 -0
- data/lib/yuzu/postprocessors/contents_without_first_paragraph.rb +20 -0
- data/lib/yuzu/postprocessors/excerpt.rb +23 -0
- data/lib/yuzu/postprocessors/first_paragraph.rb +16 -0
- data/lib/yuzu/postprocessors/pagination.rb +35 -0
- data/lib/yuzu/postprocessors/recent_posts.rb +27 -0
- data/lib/yuzu/postprocessors/thumbnails.rb +48 -0
- data/lib/yuzu/preprocessors/base.rb +71 -0
- data/lib/yuzu/preprocessors/insert_contents.rb +57 -0
- data/lib/yuzu/renderers/base.rb +23 -0
- data/lib/yuzu/renderers/breadcrumb.rb +163 -0
- data/lib/yuzu/renderers/gallery.rb +24 -0
- data/lib/yuzu/renderers/title.rb +21 -0
- data/lib/yuzu/translators/base.rb +57 -0
- data/lib/yuzu/translators/markdown.rb +21 -0
- data/lib/yuzu/translators/plaintext.rb +17 -0
- data/lib/yuzu/version.rb +12 -0
- data/resources/config/compass.rb +6 -0
- data/resources/config/yuzu.yml +166 -0
- data/resources/git/post-commit +42 -0
- data/resources/sample_content/introduction/_snippets/about_insert_contents.md +3 -0
- data/resources/sample_content/introduction/about.md +6 -0
- data/resources/sample_content/introduction/advanced-posts.md +18 -0
- data/resources/sample_content/introduction/blog/blog-folder-is-special.md +8 -0
- data/resources/sample_content/introduction/getting-started.md +14 -0
- data/resources/sample_content/introduction/index.md +6 -0
- data/resources/sample_content/introduction/sample-post.md +13 -0
- data/resources/sample_projects.yml +7 -0
- data/resources/themes/minimal/_sass/print.sass +0 -0
- data/resources/themes/minimal/_sass/screen.sass +81 -0
- data/resources/themes/minimal/_templates/_block.haml +4 -0
- data/resources/themes/minimal/_templates/_blog.haml +3 -0
- data/resources/themes/minimal/_templates/_footer.haml +2 -0
- data/resources/themes/minimal/_templates/_gallery.haml +25 -0
- data/resources/themes/minimal/_templates/_head.haml +12 -0
- data/resources/themes/minimal/_templates/_header.haml +1 -0
- data/resources/themes/minimal/_templates/_menu.haml +6 -0
- data/resources/themes/minimal/_templates/blog.haml +21 -0
- data/resources/themes/minimal/_templates/generic.haml +26 -0
- data/resources/themes/minimal/_templates/home.haml +15 -0
- data/resources/themes/minimal/_templates/index.haml +21 -0
- data/resources/themes/minimal/css/print.css +0 -0
- data/resources/themes/minimal/css/screen.css +133 -0
- data/resources/themes/minimal/img/favicon.png +0 -0
- data/resources/yard/default/fulldoc/html/css/common.css +16 -0
- data/test/helper.rb +18 -0
- data/test/test_yuzu.rb +8 -0
- data/yuzu.gemspec +182 -0
- metadata +302 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
unless String.method_defined?(:titlecase)
|
3
|
+
|
4
|
+
class String
|
5
|
+
def titlecase
|
6
|
+
self.downcase.spacify.split(" ").collect {|str| str.capitalize}.join(" ")
|
7
|
+
end
|
8
|
+
|
9
|
+
def titleize
|
10
|
+
titlecase
|
11
|
+
end
|
12
|
+
|
13
|
+
def spacify
|
14
|
+
self.gsub("-", " ").gsub("_", " ")
|
15
|
+
end
|
16
|
+
|
17
|
+
def dasherize
|
18
|
+
self.gsub(" ", "-").gsub("_", "-")
|
19
|
+
end
|
20
|
+
|
21
|
+
def underline
|
22
|
+
self.gsub(/\W/, "_")
|
23
|
+
end
|
24
|
+
|
25
|
+
def includes_one_of?(arr)
|
26
|
+
tr = false
|
27
|
+
arr.each do |el|
|
28
|
+
tr ||= self.include?(el)
|
29
|
+
end
|
30
|
+
tr
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
data/lib/helpers/url.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Url holds an abstraction for web URLs, closely tied to the Path objects. This aids in translating
|
2
|
+
# on-disk paths to URLs for links.
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
class Url
|
6
|
+
# Create a new Url object.
|
7
|
+
#
|
8
|
+
# @param [String, Path] url_path The root path of the Url, from the file system, with the
|
9
|
+
# appropriate extension in place ideally.
|
10
|
+
# @param [String] prefix A prefix to add to the front of the url. This usually consists of the
|
11
|
+
# root common path on the server like http://domain.com/blah
|
12
|
+
def initialize(url_path, prefix=nil)
|
13
|
+
if url_path.is_a?(Path)
|
14
|
+
@path = url_path
|
15
|
+
|
16
|
+
elsif url_path.is_a?(String)
|
17
|
+
@path = Path.new(url_path)
|
18
|
+
|
19
|
+
elsif url_path.is_a?(Url)
|
20
|
+
@path = url_path.path
|
21
|
+
|
22
|
+
else
|
23
|
+
raise "Url must be initialized with a String, Url, or Path instance."
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
@prefix = prefix
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :path
|
31
|
+
|
32
|
+
def + (other)
|
33
|
+
if other.is_a?(String)
|
34
|
+
Url.new(@path + other, prefix=@prefix)
|
35
|
+
|
36
|
+
elsif other.is_a?(Url)
|
37
|
+
Url.new(@path + other.path.relative, prefix=@prefix)
|
38
|
+
|
39
|
+
elsif other.is_a?(Path)
|
40
|
+
Url.new(@path + other.relative_path, prefix=@prefix)
|
41
|
+
|
42
|
+
else
|
43
|
+
raise "Url + accepts String, Path, and Url instances."
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
full
|
50
|
+
end
|
51
|
+
|
52
|
+
def full(new_extension=nil)
|
53
|
+
new_extension.nil? ? join(@prefix, @path) : join(@prefix, @path.with_extension(new_extension))
|
54
|
+
end
|
55
|
+
|
56
|
+
# Join a set of paths together
|
57
|
+
def join(prefix, path, suffix=nil)
|
58
|
+
root = prefix.nil? ? path.relative : prefix + "/" + path.relative
|
59
|
+
suffix.nil? ? root : root + "/" + suffix
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
data/lib/html/base.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
# Html provides a concise way of programmatically expressing HTML tags and structure.
|
2
|
+
#
|
3
|
+
# This enables one to express a list like this:
|
4
|
+
#
|
5
|
+
# Html::UnorderedList.new << (Html::ListItem.new << "first") + (Html::ListItem.new << "second")
|
6
|
+
#
|
7
|
+
# which results in:
|
8
|
+
#
|
9
|
+
# <ul><li>first</li><li>second</li></ul>
|
10
|
+
#
|
11
|
+
# The << operator means "contains", and reduces an Html object and a string to another string. So
|
12
|
+
# after the << operation, the tags just obey String semantics.
|
13
|
+
#
|
14
|
+
# Commonly used nested tags can be composited and deployed as templates multiple times.
|
15
|
+
#
|
16
|
+
# title_link = Html::H1.new << Html::Link(:href => "http://mysite.com")
|
17
|
+
# title_link << "My Site"
|
18
|
+
#
|
19
|
+
# which results in:
|
20
|
+
#
|
21
|
+
# <h1><a href="http://mysite.com">My Site</a></h1>
|
22
|
+
#
|
23
|
+
# This is seemingly more verbose that writing it directly, but it enables you to write HTML without
|
24
|
+
# having to do string interpolation and concatenation, and it doesn't imbue Ruby code with a lot of
|
25
|
+
# HTML-related strings.
|
26
|
+
#
|
27
|
+
# words = %w(hello doctor name continue yesterday tomorrow)
|
28
|
+
# Html::UnorderedList.new << words.collect {|w| Html::ListItem.new(:class => "class-#{w}") << w}.join
|
29
|
+
#
|
30
|
+
# which will yield:
|
31
|
+
#
|
32
|
+
# <ul>
|
33
|
+
# <li class="class-hello">hello</li>
|
34
|
+
# <li class="class-doctor">doctor</li>
|
35
|
+
# <li class="class-name">name</li>
|
36
|
+
# <li class="class-continue">continue</li>
|
37
|
+
# <li class="class-yesterday">yesterday</li>
|
38
|
+
# <li class="class-tomorrow">tomorrow</li>
|
39
|
+
# </ul>
|
40
|
+
|
41
|
+
module Html
|
42
|
+
# The base Html class provides functionality for wrapping HTML tags, e.g. <div>...</div>
|
43
|
+
class Base
|
44
|
+
def initialize(attr={})
|
45
|
+
@attr = attr
|
46
|
+
end
|
47
|
+
|
48
|
+
@tag = "div"
|
49
|
+
def self.tag
|
50
|
+
@tag
|
51
|
+
end
|
52
|
+
|
53
|
+
def tag
|
54
|
+
self.class.tag
|
55
|
+
end
|
56
|
+
|
57
|
+
def attributes
|
58
|
+
@attr.length == 0 ? "" : @attr.collect {|key, value| " #{key.to_s}='#{value}'"}.join
|
59
|
+
end
|
60
|
+
|
61
|
+
def processed_output(contents)
|
62
|
+
"<#{tag}#{attributes}>#{contents}</#{tag}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
def << (other)
|
66
|
+
if other.is_a?(String)
|
67
|
+
processed_output(other)
|
68
|
+
else
|
69
|
+
Composite.new(self, other)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Class that sets off the tag by newlines to aid in readability for raw output.
|
75
|
+
class Container < Base
|
76
|
+
def processed_output(contents)
|
77
|
+
"\n<#{tag}#{attributes}>\n#{contents}\n</#{tag}>\n"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Item < Base
|
82
|
+
def processed_output(contents)
|
83
|
+
"<#{tag}#{attributes}>#{contents}</#{tag}>\n"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Class for compositing nested tags togther and using them multiple times in different contexts.
|
88
|
+
class Composite
|
89
|
+
def initialize(first, second)
|
90
|
+
@first = first
|
91
|
+
@second = second
|
92
|
+
end
|
93
|
+
|
94
|
+
def << (other)
|
95
|
+
if other.is_a?(String)
|
96
|
+
@first << (@second << other)
|
97
|
+
else
|
98
|
+
Composite.new(self, other)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# HTML flags are those that don't have a closing tag, e.g. <img href="">
|
104
|
+
class Flag < Base
|
105
|
+
def to_s
|
106
|
+
"<#{tag}#{attributes}>"
|
107
|
+
end
|
108
|
+
|
109
|
+
def << (other)
|
110
|
+
self.to_s + other
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Handler for adding HTML comments inline.
|
115
|
+
class Comment < Base
|
116
|
+
def << (other)
|
117
|
+
"\n<!-- #{other} -->\n"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Class handler for <div> tags.
|
122
|
+
class Div < Container
|
123
|
+
instance_variable_set(:@tag, "div")
|
124
|
+
end
|
125
|
+
|
126
|
+
# Class handler for <a> links.
|
127
|
+
class Link < Base
|
128
|
+
instance_variable_set(:@tag, "a")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Class handler for <li> list item tags.
|
132
|
+
class ListItem < Item
|
133
|
+
instance_variable_set(:@tag, "li")
|
134
|
+
end
|
135
|
+
|
136
|
+
# Class handler for <ul> unordered lists.
|
137
|
+
class UnorderedList < Container
|
138
|
+
instance_variable_set(:@tag, "ul")
|
139
|
+
end
|
140
|
+
|
141
|
+
# Handler for <ol> ordered lists.
|
142
|
+
class OrderedList < Container
|
143
|
+
instance_variable_set(:@tag, "ol")
|
144
|
+
end
|
145
|
+
|
146
|
+
# Handler for <h1> headers.
|
147
|
+
class H1 < Item
|
148
|
+
instance_variable_set(:@tag, "h1")
|
149
|
+
end
|
150
|
+
|
151
|
+
# Handler for <h2> headers.
|
152
|
+
class H2 < Item
|
153
|
+
instance_variable_set(:@tag, "h2")
|
154
|
+
end
|
155
|
+
|
156
|
+
# Handler for <h3> headers.
|
157
|
+
class H3 < Item
|
158
|
+
instance_variable_set(:@tag, "h3")
|
159
|
+
end
|
160
|
+
|
161
|
+
# Handler for <h4> headers.
|
162
|
+
class H4 < Item
|
163
|
+
instance_variable_set(:@tag, "h4")
|
164
|
+
end
|
165
|
+
|
166
|
+
# Handler for <span> tags.
|
167
|
+
class Span < Base
|
168
|
+
instance_variable_set(:@tag, "span")
|
169
|
+
end
|
170
|
+
|
171
|
+
# Handler for <p> paragraph tags.
|
172
|
+
class Paragraph < Container
|
173
|
+
instance_variable_set(:@tag, "p")
|
174
|
+
end
|
175
|
+
|
176
|
+
# Handler for <img> images.
|
177
|
+
class Image < Flag
|
178
|
+
instance_variable_set(:@tag, "img")
|
179
|
+
end
|
180
|
+
|
181
|
+
# Handler for <br> line breaks.
|
182
|
+
class Break < Flag
|
183
|
+
instance_variable_set(:@tag, "br")
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Require service.rb first.
|
2
|
+
require 'uploader/service'
|
3
|
+
require 'uploader/suppressor'
|
4
|
+
require 'uploader/config'
|
5
|
+
|
6
|
+
Dir["#{File.dirname(__FILE__)}/*"].each do |service|
|
7
|
+
require service if service.include?("_service")
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
module Uploader
|
12
|
+
class UnrecognizedService < Exception; end
|
13
|
+
|
14
|
+
class UploadManager
|
15
|
+
|
16
|
+
def initialize(config, service_override=nil)
|
17
|
+
@config = config # UploaderConfig
|
18
|
+
@service_override = service_override
|
19
|
+
@suppressor = Suppressor.new
|
20
|
+
|
21
|
+
set_service!
|
22
|
+
connect!
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_service!
|
26
|
+
service_name, service_class = get_service
|
27
|
+
service_config_hash = @config.send(service_name).merge({:verbose? => @config.verbose?})
|
28
|
+
|
29
|
+
@service = service_class.new(UploaderConfig.new(service_config_hash))
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_service
|
33
|
+
service_key = (@service_override || @config.connection).to_sym
|
34
|
+
|
35
|
+
if Service.is_registered?(service_key)
|
36
|
+
$stderr.puts "Using service #{service_key}" if @config.verbose?
|
37
|
+
|
38
|
+
return service_key, Service.services[service_key]
|
39
|
+
else
|
40
|
+
raise UnrecognizedService
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def connect!
|
45
|
+
@service.connect!
|
46
|
+
end
|
47
|
+
|
48
|
+
def upload(remote_path, contents)
|
49
|
+
@service.upload(remote_path, contents)
|
50
|
+
end
|
51
|
+
|
52
|
+
def close!
|
53
|
+
@service.close!
|
54
|
+
@suppressor.close!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Uploader
|
3
|
+
|
4
|
+
class UploaderConfig
|
5
|
+
def initialize(config_hash)
|
6
|
+
@config_hash = config_hash
|
7
|
+
|
8
|
+
(class << self; self; end).class_eval do
|
9
|
+
config_hash.each_pair do |key, value|
|
10
|
+
define_method(key) do
|
11
|
+
value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'uploader/base'
|
2
|
+
require 'uploader/service'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
|
6
|
+
module Uploader
|
7
|
+
GREEN = "\033[32m"
|
8
|
+
ENDC = "\033[0m"
|
9
|
+
|
10
|
+
class FileSystemService < Service
|
11
|
+
def connect!
|
12
|
+
end
|
13
|
+
|
14
|
+
def upload(remote_path, contents)
|
15
|
+
raise UploadArgumentError if not remote_path.is_a?(Path)
|
16
|
+
|
17
|
+
contents_to_upload, binmode = get_upload_contents(contents)
|
18
|
+
|
19
|
+
copy_contents_to_file_system(remote_path, contents_to_upload, binmode)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_upload_contents(contents)
|
23
|
+
binmode = false
|
24
|
+
if contents.is_a?(File)
|
25
|
+
contents_to_upload = contents.read
|
26
|
+
binmode = true
|
27
|
+
|
28
|
+
elsif contents.is_a?(String)
|
29
|
+
contents_to_upload = contents
|
30
|
+
|
31
|
+
else
|
32
|
+
raise UnrecognizedContentType
|
33
|
+
end
|
34
|
+
|
35
|
+
return contents_to_upload, binmode
|
36
|
+
end
|
37
|
+
|
38
|
+
def copy_contents_to_file_system(remote_path, contents, binary=true)
|
39
|
+
destination = Path.new(@config.destination) + remote_path.relative
|
40
|
+
if @config.verbose?
|
41
|
+
$stderr.puts %Q{Copying #{GREEN}#{remote_path}#{ENDC} to the file system
|
42
|
+
--> #{destination}}
|
43
|
+
else
|
44
|
+
$stderr.print "."
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
f = File.open(destination.absolute, "w+")
|
49
|
+
|
50
|
+
rescue => detail
|
51
|
+
$stderr.puts detail.message
|
52
|
+
$stderr.puts "Attempting to create the path."
|
53
|
+
|
54
|
+
# Assume the directories leading to the file don't exist. Create them.
|
55
|
+
FileUtils::mkdir_p(destination.dirname)
|
56
|
+
|
57
|
+
f = File.open(destination.absolute, "w+")
|
58
|
+
end
|
59
|
+
|
60
|
+
unless f.nil?
|
61
|
+
f.syswrite(contents)
|
62
|
+
f.close
|
63
|
+
$stderr.puts "Done with #{destination.relative}." if @config.verbose?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Service.register(:filesystem => FileSystemService)
|
69
|
+
Service.register(:stage => FileSystemService)
|
70
|
+
Service.register(:preview => FileSystemService)
|
71
|
+
end
|
72
|
+
|