yuzu 0.2.1.pre

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 (116) hide show
  1. data/.document +5 -0
  2. data/.yardopts +7 -0
  3. data/ChangeLog.md +8 -0
  4. data/Gemfile +26 -0
  5. data/Gemfile.lock +30 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +52 -0
  8. data/Rakefile +62 -0
  9. data/bin/yuzu +17 -0
  10. data/docs/About.md +19 -0
  11. data/docs/GettingStarted.md +48 -0
  12. data/docs/Reference.md +97 -0
  13. data/lib/helpers/object.rb +19 -0
  14. data/lib/helpers/path.rb +296 -0
  15. data/lib/helpers/string.rb +35 -0
  16. data/lib/helpers/system_checks.rb +10 -0
  17. data/lib/helpers/url.rb +64 -0
  18. data/lib/html/base.rb +187 -0
  19. data/lib/uploader/base.rb +59 -0
  20. data/lib/uploader/config.rb +19 -0
  21. data/lib/uploader/filesystem_service.rb +72 -0
  22. data/lib/uploader/ftp_service.rb +90 -0
  23. data/lib/uploader/s3_service.rb +135 -0
  24. data/lib/uploader/service.rb +57 -0
  25. data/lib/uploader/suppressor.rb +25 -0
  26. data/lib/yuzu.rb +6 -0
  27. data/lib/yuzu/argparse.rb +60 -0
  28. data/lib/yuzu/command.rb +104 -0
  29. data/lib/yuzu/commands/base.rb +150 -0
  30. data/lib/yuzu/commands/create.rb +68 -0
  31. data/lib/yuzu/commands/generate.rb +95 -0
  32. data/lib/yuzu/commands/help.rb +20 -0
  33. data/lib/yuzu/commands/preview.rb +58 -0
  34. data/lib/yuzu/commands/publish.rb +43 -0
  35. data/lib/yuzu/commands/stage.rb +62 -0
  36. data/lib/yuzu/commands/watch.rb +70 -0
  37. data/lib/yuzu/content/blog_post.rb +45 -0
  38. data/lib/yuzu/content/sample_project.rb +130 -0
  39. data/lib/yuzu/core/config.rb +154 -0
  40. data/lib/yuzu/core/layout.rb +85 -0
  41. data/lib/yuzu/core/paginated_file.rb +69 -0
  42. data/lib/yuzu/core/registrar.rb +32 -0
  43. data/lib/yuzu/core/siteroot.rb +57 -0
  44. data/lib/yuzu/core/template.rb +158 -0
  45. data/lib/yuzu/core/updater.rb +123 -0
  46. data/lib/yuzu/core/visitor.rb +44 -0
  47. data/lib/yuzu/core/website_base.rb +150 -0
  48. data/lib/yuzu/core/website_file.rb +270 -0
  49. data/lib/yuzu/core/website_folder.rb +176 -0
  50. data/lib/yuzu/filters/base.rb +86 -0
  51. data/lib/yuzu/filters/catalog.rb +248 -0
  52. data/lib/yuzu/filters/categories.rb +58 -0
  53. data/lib/yuzu/filters/currentpath.rb +35 -0
  54. data/lib/yuzu/filters/description.rb +16 -0
  55. data/lib/yuzu/filters/extension.rb +16 -0
  56. data/lib/yuzu/filters/images.rb +32 -0
  57. data/lib/yuzu/filters/linkroot.rb +35 -0
  58. data/lib/yuzu/filters/post_date.rb +45 -0
  59. data/lib/yuzu/filters/post_title.rb +66 -0
  60. data/lib/yuzu/filters/post_title_removed.rb +28 -0
  61. data/lib/yuzu/filters/sidebar.rb +26 -0
  62. data/lib/yuzu/filters/template.rb +16 -0
  63. data/lib/yuzu/generators/base.rb +44 -0
  64. data/lib/yuzu/generators/category_folders.rb +91 -0
  65. data/lib/yuzu/generators/index.rb +108 -0
  66. data/lib/yuzu/generators/paginate.rb +136 -0
  67. data/lib/yuzu/postprocessors/all_categories.rb +48 -0
  68. data/lib/yuzu/postprocessors/base.rb +34 -0
  69. data/lib/yuzu/postprocessors/contents_without_first_paragraph.rb +20 -0
  70. data/lib/yuzu/postprocessors/excerpt.rb +23 -0
  71. data/lib/yuzu/postprocessors/first_paragraph.rb +16 -0
  72. data/lib/yuzu/postprocessors/pagination.rb +35 -0
  73. data/lib/yuzu/postprocessors/recent_posts.rb +27 -0
  74. data/lib/yuzu/postprocessors/thumbnails.rb +48 -0
  75. data/lib/yuzu/preprocessors/base.rb +71 -0
  76. data/lib/yuzu/preprocessors/insert_contents.rb +57 -0
  77. data/lib/yuzu/renderers/base.rb +23 -0
  78. data/lib/yuzu/renderers/breadcrumb.rb +163 -0
  79. data/lib/yuzu/renderers/gallery.rb +24 -0
  80. data/lib/yuzu/renderers/title.rb +21 -0
  81. data/lib/yuzu/translators/base.rb +57 -0
  82. data/lib/yuzu/translators/markdown.rb +21 -0
  83. data/lib/yuzu/translators/plaintext.rb +17 -0
  84. data/lib/yuzu/version.rb +12 -0
  85. data/resources/config/compass.rb +6 -0
  86. data/resources/config/yuzu.yml +166 -0
  87. data/resources/git/post-commit +42 -0
  88. data/resources/sample_content/introduction/_snippets/about_insert_contents.md +3 -0
  89. data/resources/sample_content/introduction/about.md +6 -0
  90. data/resources/sample_content/introduction/advanced-posts.md +18 -0
  91. data/resources/sample_content/introduction/blog/blog-folder-is-special.md +8 -0
  92. data/resources/sample_content/introduction/getting-started.md +14 -0
  93. data/resources/sample_content/introduction/index.md +6 -0
  94. data/resources/sample_content/introduction/sample-post.md +13 -0
  95. data/resources/sample_projects.yml +7 -0
  96. data/resources/themes/minimal/_sass/print.sass +0 -0
  97. data/resources/themes/minimal/_sass/screen.sass +81 -0
  98. data/resources/themes/minimal/_templates/_block.haml +4 -0
  99. data/resources/themes/minimal/_templates/_blog.haml +3 -0
  100. data/resources/themes/minimal/_templates/_footer.haml +2 -0
  101. data/resources/themes/minimal/_templates/_gallery.haml +25 -0
  102. data/resources/themes/minimal/_templates/_head.haml +12 -0
  103. data/resources/themes/minimal/_templates/_header.haml +1 -0
  104. data/resources/themes/minimal/_templates/_menu.haml +6 -0
  105. data/resources/themes/minimal/_templates/blog.haml +21 -0
  106. data/resources/themes/minimal/_templates/generic.haml +26 -0
  107. data/resources/themes/minimal/_templates/home.haml +15 -0
  108. data/resources/themes/minimal/_templates/index.haml +21 -0
  109. data/resources/themes/minimal/css/print.css +0 -0
  110. data/resources/themes/minimal/css/screen.css +133 -0
  111. data/resources/themes/minimal/img/favicon.png +0 -0
  112. data/resources/yard/default/fulldoc/html/css/common.css +16 -0
  113. data/test/helper.rb +18 -0
  114. data/test/test_yuzu.rb +8 -0
  115. data/yuzu.gemspec +182 -0
  116. metadata +302 -0
@@ -0,0 +1,86 @@
1
+ require 'core/registrar'
2
+
3
+ module Yuzu::Filters
4
+ include Yuzu::Registrar
5
+
6
+ # Filters are the primary means to derive information from a given source file and place new
7
+ # contents into it before it is placed in a layout.
8
+ #
9
+ # There are 3 stages of filtering that happen to each file.
10
+ #
11
+ # 1. prefilter -- replacing LINKROOT and CURRENTPATH, so the next phase has the proper paths
12
+ # 2. filter -- transforming contents
13
+ # 3. postfilter -- replacing LINKROOT and CURRENTPATH again
14
+ class Filter < Register
15
+ @@filters = {}
16
+ def self.registry
17
+ :filters
18
+ end
19
+ def self.filters
20
+ @@filters
21
+ end
22
+
23
+ attr_reader :name, :directive
24
+
25
+ def initialize
26
+ @name = :directive
27
+ @directive = "DIRECTIVE"
28
+ end
29
+
30
+ def filter_type
31
+ [:filter]
32
+ end
33
+
34
+ def default(website_file=nil)
35
+ nil
36
+ end
37
+
38
+ def value(website_file)
39
+ get_value(website_file) || default(website_file)
40
+ end
41
+
42
+ def get_value(website_file)
43
+ match(website_file.raw_contents)
44
+ end
45
+
46
+ def match(contents)
47
+ get_match(contents)
48
+ end
49
+
50
+ def get_match(contents)
51
+ m = contents.match(regex)
52
+ m.nil? ? nil : m[1]
53
+ end
54
+
55
+ # Returns the contents to replace the directive with as written.
56
+ #
57
+ # @param [WebsiteFile] website_file The page in which the directive appears
58
+ # @param [String, nil] processing_contents The contents of the given WebsiteFile as they are
59
+ # being transformed by processing.
60
+ # @return [String] What to replace the directive with.
61
+ def replacement(website_file, processing_contents=nil)
62
+ ""
63
+ end
64
+
65
+ def regex
66
+ Regexp.new('^\s*' + @directive.to_s + '\(([\w\s\.\,\'\"\/\-:]*?)\)')
67
+ end
68
+
69
+ def process(website_file, processing_contents)
70
+ m = processing_contents.match(regex)
71
+
72
+ while not m.nil?
73
+ repl = replacement(website_file, processing_contents)
74
+
75
+ # Remove the next match.
76
+ processing_contents = processing_contents.sub(regex, repl.to_s)
77
+
78
+ # Find any others...
79
+ m = processing_contents.match(regex)
80
+ end
81
+
82
+ processing_contents
83
+ end
84
+ end
85
+ end
86
+
@@ -0,0 +1,248 @@
1
+ require 'filters/base'
2
+ require 'core/template'
3
+ require 'helpers/path'
4
+ require 'html/base'
5
+
6
+
7
+ module Yuzu::Filters
8
+ include Yuzu::Core
9
+
10
+ class CatalogFilter < Filter
11
+ def initialize
12
+ @name = :catalog
13
+ @directive = "INSERTCATALOG"
14
+ end
15
+
16
+ def value(website_file)
17
+ nil
18
+ end
19
+
20
+ def replacement(website_file, processing_contents=nil)
21
+ catalog = Yuzu::Filters.catalog_for(website_file, match(processing_contents))
22
+
23
+ if catalog.should_paginate? and catalog.num_pages > 1
24
+ website_file.stash(:catalog => catalog)
25
+ end
26
+
27
+ return catalog.render
28
+ end
29
+ end
30
+ Filter.register(:catalog => CatalogFilter)
31
+
32
+
33
+ # Create a Catalog instance for a given match
34
+ #
35
+ # @param [WebsiteFile] website_file The file in which the catalog is being rendered.
36
+ # @param [String] match_string The match given by the filter, e.g. "page:1, per_row:3, ..."
37
+ # @return [Catalog] The catalog object responsible for rendering the pages specified.
38
+ def catalog_for(website_file, match_string)
39
+ kwds = Yuzu::Filters.get_kwds(match_string)
40
+ Catalog.new(kwds, website_file, match_string)
41
+ end
42
+ module_function :catalog_for
43
+
44
+ # Returns a Hash of the keyword arguments contained in the inner match string of the tag:
45
+ #
46
+ # INSERTCATALOG(page: 1, count:10)
47
+ #
48
+ # yields
49
+ #
50
+ # {:page => 1, :count => 10}
51
+ #
52
+ # @param [String] match_string The text inside the tag match.
53
+ # @return [Hash] The key to value pairs.
54
+ def get_kwds(match_string)
55
+ pairs = match_string.split(",").collect {|pair| pair.strip}
56
+
57
+ kwds = {}
58
+ pairs.each do |pair|
59
+ key, val = pair.split(":").collect {|el| el.strip}
60
+ kwds[key.to_sym] = val
61
+ end
62
+
63
+ kwds
64
+ end
65
+ module_function :get_kwds
66
+
67
+
68
+ # Catalogs render one page of collected contents and have no knowledge of pagination. The
69
+ # auto-pagination happens earlier as part of the generation process.
70
+ class Catalog
71
+ include Helpers
72
+ attr_reader :website_file
73
+
74
+ def initialize(kwds, website_file, original_match_string)
75
+ @kwds = kwds
76
+ @website_file = website_file
77
+ @original_match_string = original_match_string
78
+
79
+ @siteroot = website_file.root
80
+ end
81
+
82
+ # Define accessors for each of the given keyword arguments.
83
+ @@kwd_defaults = {
84
+ :template => '_block.haml',
85
+ :total => 1000,
86
+ :per_page => 10,
87
+ :per_row => 1,
88
+ :page => 1,
89
+ :offset => 0,
90
+ :category => nil
91
+ }
92
+ @@kwd_defaults.each_pair do |key, default_value|
93
+ define_method key do
94
+ if @kwds.has_key?(key)
95
+ # The user's arguments always come in as a String, so this converts the argument into its
96
+ # appropriate type as specified by the defaults Hash.
97
+ convert_method = get_default_type_method(key)
98
+ convert_method.nil? ? @kwds[key] : @kwds[key].send(convert_method)
99
+ else
100
+ default_value
101
+ end
102
+ end
103
+ end
104
+
105
+ def get_default_type_method(key)
106
+ klass = get_default_type(key)
107
+ if klass == String
108
+ :to_s
109
+ elsif klass == Fixnum
110
+ :to_i
111
+ elsif klass == Float
112
+ :to_f
113
+ else
114
+ nil
115
+ end
116
+ end
117
+
118
+ def get_default_type(key)
119
+ @@kwd_defaults.has_key?(key) ? @@kwd_defaults[key].class : nil
120
+ end
121
+
122
+ def should_paginate?
123
+ num_total_files > number_of_files_to_show
124
+ end
125
+
126
+ def num_total_files
127
+ [target_files.length, total].min
128
+ end
129
+
130
+ def num_pages
131
+ return 1 if not should_paginate?
132
+ (num_total_files.to_f / per_page.to_f).ceil
133
+ end
134
+
135
+ def original_directive
136
+ # TODO build a regex forgiving of whitespace
137
+ "INSERTCATALOG(#{@original_match_string})"
138
+ end
139
+
140
+ def directive_for_page(page)
141
+ with_page = @kwds.merge({:page => page})
142
+ args = with_page.collect {|key, val| "#{key}:#{val}"}.join(", ")
143
+ "INSERTCATALOG(#{args})"
144
+ end
145
+
146
+ def formatted_directive
147
+ args = @kwds.collect {|key, val| "#{key}:#{val}"}.join(", ")
148
+ "INSERTCATALOG(#{args})"
149
+ end
150
+
151
+ def render
152
+ if well_formed?
153
+ rows = []
154
+ num_rows_this_page.times do |row|
155
+ rows.push(render_nth_row(row))
156
+ end
157
+ rows.join("\n")
158
+ else
159
+ Html::Comment.new << "Error in processing the catalog. Got #{formatted_directive}"
160
+ end
161
+ end
162
+
163
+ def render_nth_row(row)
164
+ start = row * per_row
165
+ stop = (row + 1) * per_row
166
+ files_this_row = files_to_render_this_page[start...stop]
167
+ if files_this_row.empty?
168
+ Html::Div.new(:class => 'row') << Html::Comment.new << "No files in this row."
169
+ else
170
+ render_row(files_this_row)
171
+ end
172
+ end
173
+
174
+ def render_row(files)
175
+ rendered_files = files.collect {|file| render_post(file)}.join("\n")
176
+ Html::Div.new(:class => 'row') << rendered_files
177
+ end
178
+
179
+ def render_post(file)
180
+ partial.render(file, {:klass => css_class})
181
+ end
182
+
183
+ def css_class
184
+ num_columns_12 = (12.0 / per_row).floor
185
+ "span#{num_columns_12}"
186
+ end
187
+
188
+ def partial
189
+ Yuzu::Core::HamlTemplate.new(template)
190
+ end
191
+
192
+ def well_formed?
193
+ @kwds.has_key?(:path)
194
+ end
195
+
196
+ def target_folder
197
+ case
198
+ when (not well_formed?)
199
+ nil
200
+ when @kwds[:path] == ""
201
+ @siteroot
202
+ else
203
+ search_path = Path.new(@kwds[:path])
204
+ @siteroot.find_file_by_path(search_path)
205
+ end
206
+ end
207
+
208
+ def target_files
209
+ @target_files ||= get_target_files
210
+ end
211
+
212
+ def get_target_files
213
+ return [] if target_folder.nil?
214
+ unsorted = target_folder.all_processable_children.reject {|node| node.index?}
215
+ if not category.nil?
216
+ unsorted = unsorted.select {|file| file_has_category?(file)}
217
+ end
218
+ unsorted.sort {|a, b| b.post_date <=> a.post_date}
219
+ end
220
+
221
+ def file_has_category?(file)
222
+ file.categories.each do |cat|
223
+ if cat.name == category.downcase.dasherize
224
+ return true
225
+ end
226
+ end
227
+ return false
228
+ end
229
+
230
+ # Returns an array of WebsiteFile objects that are the contents of the catalog on this page.
231
+ def files_to_render_this_page
232
+ start = (page - 1) * per_page + offset
233
+ stop = page * per_page + offset
234
+ target_files[start...stop]
235
+ end
236
+
237
+ def num_rows_this_page
238
+ (number_of_files_to_show.to_f / per_row.to_f).ceil
239
+ end
240
+
241
+ def number_of_files_to_show
242
+ [total, per_page, target_files.length, page * per_page].min
243
+ end
244
+
245
+ end
246
+ end
247
+
248
+
@@ -0,0 +1,58 @@
1
+ require 'filters/base'
2
+ require 'helpers/url'
3
+ require 'helpers/path'
4
+
5
+ module Yuzu::Filters
6
+ class CategoriesFilter < Filter
7
+ def initialize
8
+ @name = :categories
9
+ @directive = "CATEGORIES"
10
+ end
11
+
12
+ def default(website_file)
13
+ [Category.new("uncategorized", website_file)]
14
+ end
15
+
16
+ def get_value(website_file)
17
+ m = match(website_file.raw_contents)
18
+ return default(website_file) if m.nil?
19
+
20
+ category_list = m.split(",")
21
+ category_list.collect! {|cat| cat.strip.downcase}
22
+ category_list.reject! {|cat| cat.empty?}
23
+ category_list.collect {|cat| Category.new(cat, website_file)}
24
+ end
25
+ end
26
+ Filter.register(:categories => CategoriesFilter)
27
+
28
+
29
+ class Category
30
+ attr_reader :name
31
+
32
+ def initialize(name, website_file)
33
+ @name = name.dasherize.downcase
34
+ @website_file = website_file
35
+ end
36
+
37
+ def link
38
+ Html::Link.new(:href => url) << @name.titlecase
39
+ end
40
+
41
+ def url
42
+ blog_folder.link_url + "/" + @name
43
+ end
44
+
45
+ def path
46
+ Helpers::Path.new(blog_folder.path.name, @name)
47
+ end
48
+
49
+ def blog_folder
50
+ @website_file.blog_folder
51
+ end
52
+
53
+ def <=>(other)
54
+ @name <=> other.name
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,35 @@
1
+ require 'filters/base'
2
+ require 'helpers/url'
3
+
4
+ module Yuzu::Filters
5
+ class CurrentpathFilter < Filter
6
+ include Helpers
7
+
8
+ def initialize
9
+ @name = :currentpath
10
+ @directive = "CURRENTPATH"
11
+ end
12
+
13
+ def filter_type
14
+ # Filter the LINKROOT in IMAGES and other path-dependent tags first, so they have the proper
15
+ # paths to search for. Then process LINKROOT afterwards.
16
+ [:prefilter, :postfilter]
17
+ end
18
+
19
+ def regex
20
+ /CURRENTPATH/
21
+ end
22
+
23
+ def get_value(website_file)
24
+ linkroot = website_file.config.linkroot
25
+ pathname = website_file.path.dirname
26
+ Url.new(pathname, prefix=linkroot)
27
+ end
28
+
29
+ def replacement(website_file, processing_contents=nil)
30
+ get_value(website_file)
31
+ end
32
+ end
33
+ Filter.register(:currentpath => CurrentpathFilter)
34
+ end
35
+
@@ -0,0 +1,16 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class DescriptionFilter < Filter
5
+ def initialize
6
+ @name = :description
7
+ @directive = "DESCRIPTION"
8
+ end
9
+
10
+ def default(website_file=nil)
11
+ ""
12
+ end
13
+ end
14
+ Filter.register(:description => DescriptionFilter)
15
+ end
16
+