flutterby 0.3.1 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bfb4189fdcf9b5640df468a2818ae3d2f647c71
4
- data.tar.gz: adb8399cc0fe5f5c8ca452f8570c8b19fd74aacb
3
+ metadata.gz: 83e24d1e73103a5cef7b60efcf5a21951e474c66
4
+ data.tar.gz: f25f5763a2a10b7190e9ea5a827ef716bba729f7
5
5
  SHA512:
6
- metadata.gz: fcdb6900c5bd5aee4c1425bb226b110a151413a27af13f368aa317326521c9a0afe0be656f48413aec7f9bad327642d3ff2c0360c37267b0a271fa83a7e78272
7
- data.tar.gz: 832097dcf92dd891160a04a1d164a392efe316aa6a8d79f92e660b76232fab0bf18d9934ce1f6d09c85fa8edc5b2765ee61a28cb64bb6241d197731b565ff649
6
+ metadata.gz: fc8ecf0efc0a1615d0149b1a94b0eb3fef7cd27db54147de26238646313f2dc679b74335cc69671364f1d04f43c96d72112ff7b596a27c883256808449622aa4
7
+ data.tar.gz: d7ed0d77dde3726cc718c0420f1d1f3a5732c17a9906329d945b7eb607ccce3fa183659a7b92787edcb024bb39883f04cbcf6982a43675da21be31b576ba860d
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Version History
2
2
 
3
+ ### 0.4.0 (2017-01-21)
4
+
5
+ - **NEW:** Flutterby views now have a `tag` helper method available that can generate HTML tags programatically.
6
+ - **NEW:** Flutterby views now have a `link_to` helper method available that renders link tags. You can use a URL string as the link target, eg. `link_to "Home", "/"`, or any Flutterby node, eg. `link_to "Blog", blog_node`.
7
+ - **NEW:** Flutterby views now have a `debug` helper that will dump its argument's YAML representation into a `<pre>` HTML tag (similar to Rails.)
8
+
9
+
3
10
  ### 0.3.1 (2017-01-15)
4
11
 
5
12
  - **NEW:** Flutterby now uses ActiveSupport. It's a big dependency, but there's just so much useful goodness in there -- let's ride on the shoulders of that giant! This allows you to use all the neat little ActiveSupport toys you may know from Rails in your Flutterby project.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Flutterby
2
2
 
3
- ### A very, very good static site generator.
3
+ ### A flexible, Ruby-powered static site generator.
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/flutterby.svg)](https://badge.fury.io/rb/flutterby) [![Build Status](https://travis-ci.org/hmans/flutterby.svg?branch=master)](https://travis-ci.org/hmans/flutterby) [![license](https://img.shields.io/github/license/hmans/flutterby.svg)](https://github.com/hmans/flutterby/blob/master/LICENSE.txt) ![Status](https://img.shields.io/badge/status-active-brightgreen.svg)
6
6
 
@@ -18,6 +18,9 @@
18
18
  - [Blog post introducing Flutterby](http://hmans.io/posts/2017/01/11/flutterby.html)
19
19
  - [New project template](https://github.com/hmans/flutterby/tree/master/lib/templates/new_project) (example code)
20
20
  - [Version History](https://github.com/hmans/flutterby/blob/master/CHANGES.md)
21
+ - [Roadmap](https://github.com/hmans/flutterby/projects/1)
22
+ - [Sites built with Flutterby](https://github.com/hmans/flutterby/wiki/Sites-built-with-Flutterby) (add yours!)
23
+
21
24
 
22
25
  ## Installation & Basic Usage
23
26
 
@@ -41,22 +44,6 @@ Flutterby comes with a local development server that will automatically pick up
41
44
  **Note**: by default, both the `build` and `serve` commands assume `./site/` to be the source directory and `./_build/` to be the export directory. Please refer to `flutterby help` to see how you can override these.
42
45
 
43
46
 
44
- ## Examples
45
-
46
- Please refer to the [Sites built with Flutterby](https://github.com/hmans/flutterby/wiki/Sites-built-with-Flutterby) page on the Flutterby Wiki for some examples.
47
-
48
-
49
- ## Roadmap
50
-
51
- Flutterby is young, but already quite functional. Here's a list of changes I'm intending to make in the near future -- if you want to work on any of these, let me know!
52
-
53
- - Performance! Right now, the source file for every node is read into RAM as a whole. Not a big problem when you're building a small site, but add some larger images, and you'll have one.
54
- - Change `flutterby serve` so it doesn't always regenerate the _entire_ site graph when a file is modified.
55
- - Extract filters (like Slim, Sass etc.) to separate gems, to make the core gem more light-weight.
56
- - Improve the template site (`flutterby new`).
57
- - Produce a fun screencast to explain what the heck is going on here!
58
- - Write even more tests!
59
-
60
47
 
61
48
  ## Notes
62
49
 
@@ -60,7 +60,7 @@ module Flutterby
60
60
  root.stage!
61
61
  say color("🌲 Read #{root.tree_size} nodes.", :green, :bold)
62
62
 
63
- say color("🌤 Serving your site on port #{options.port}. Enjoy!", :bold)
63
+ say color("🌤 Serving your Flutterby site on http://localhost:#{options.port} - enjoy! \\o/", :bold)
64
64
  server = Flutterby::Server.new(root, port: options.port)
65
65
  server.run!
66
66
  end
@@ -75,6 +75,7 @@ module Flutterby
75
75
 
76
76
  say color("🏗 Creating a new Flutterby project in #{path}...", :bold)
77
77
  directory("new_project", path)
78
+ chmod("bin/flutterby", 0755)
78
79
  in_root { bundle_install }
79
80
  end
80
81
 
@@ -2,7 +2,8 @@ require 'benchmark'
2
2
 
3
3
  module Flutterby
4
4
  class Node
5
- attr_accessor :name, :ext, :source, :body
5
+ attr_accessor :name, :ext, :source
6
+ attr_writer :body
6
7
  attr_reader :filters, :parent, :fs_path, :children, :paths
7
8
 
8
9
  def initialize(name, parent: nil, fs_path: nil, source: nil)
@@ -23,287 +24,278 @@ module Flutterby
23
24
  reload!
24
25
  end
25
26
 
26
- #
27
- # Children
28
- #
29
-
30
- def register_url!
31
- if file? && should_publish?
32
- root.paths[url] = self
27
+ concerning :Children do
28
+ def register_url!
29
+ if file? && should_publish?
30
+ root.paths[url] = self
31
+ end
33
32
  end
34
- end
35
33
 
36
- def find_child(name)
37
- if name.include?(".")
38
- @children.find { |c| c.full_name == name }
39
- else
40
- @children.find { |c| c.name == name }
41
- end
42
- end
43
-
44
- def tree_size
45
- children.inject(children.length) do |count, child|
46
- count + child.tree_size
34
+ def find_child(name)
35
+ if name.include?(".")
36
+ @children.find { |c| c.full_name == name }
37
+ else
38
+ @children.find { |c| c.name == name }
39
+ end
47
40
  end
48
- end
49
41
 
50
- def parent=(new_parent)
51
- if @parent
52
- @parent.children.delete(self)
42
+ def tree_size
43
+ children.inject(children.length) do |count, child|
44
+ count + child.tree_size
45
+ end
53
46
  end
54
47
 
55
- @parent = new_parent
56
-
57
- @parent.children << self
58
- end
59
-
60
- # Returns all children that will compile to a HTML page.
61
- #
62
- def pages
63
- children.select { |c| c.ext == "html" && c.should_publish? }
64
- end
65
-
66
- #
67
- # Path Algebra
68
- #
69
-
70
- def path
71
- parent ? ::File.join(parent.path, full_name) : full_name
72
- end
73
-
74
- def url
75
- ::File.join(parent ? parent.url : "/", full_name)
76
- end
77
-
78
- def full_fs_path(base:)
79
- ::File.expand_path(::File.join(base, full_name))
80
- end
48
+ def parent=(new_parent)
49
+ if @parent
50
+ @parent.children.delete(self)
51
+ end
81
52
 
53
+ @parent = new_parent
82
54
 
83
- #
84
- # Tree Walking
85
- #
55
+ @parent.children << self
56
+ end
86
57
 
87
- def root
88
- parent ? parent.root : self
58
+ # Returns all children that will compile to a HTML page.
59
+ #
60
+ def pages
61
+ children.select { |c| c.ext == "html" && c.should_publish? }
62
+ end
89
63
  end
90
64
 
91
- def root?
92
- root == self
93
- end
65
+ concerning :Paths do
66
+ def path
67
+ parent ? ::File.join(parent.path, full_name) : full_name
68
+ end
94
69
 
95
- def sibling(name)
96
- parent && parent.find(name)
97
- end
70
+ def url
71
+ ::File.join(parent ? parent.url : "/", full_name)
72
+ end
98
73
 
99
- def siblings
100
- parent && parent.children
74
+ def full_fs_path(base:)
75
+ ::File.expand_path(::File.join(base, full_name))
76
+ end
101
77
  end
102
78
 
103
- def find(path)
104
- return self if path.nil? || path.empty?
105
-
106
- # remove duplicate slashes
107
- path.gsub!(%r{/+}, "/")
108
79
 
109
- case path
110
- when %r{^\./?} then
111
- parent ? parent.find($') : root.find($')
112
- when %r{^/} then
113
- root.find($')
114
- when %r{^([^/]+)/?} then
115
- child = find_child($1)
116
- $'.empty? ? child : child.find($')
80
+ concerning :Tree do
81
+ def root
82
+ parent ? parent.root : self
117
83
  end
118
- end
119
84
 
120
- # Walk the tree up, invoking the passed block for every node
121
- # found on the way, passing the node as its only argument.
122
- #
123
- def walk_up(val = nil, &blk)
124
- val = blk.call(self, val)
125
- parent ? parent.walk_up(val, &blk) : val
126
- end
85
+ def root?
86
+ root == self
87
+ end
127
88
 
128
- # Walk the graph from the root to this node. Just like walk_up,
129
- # except the block will be called on higher level nodes first.
130
- #
131
- def walk_down(val = nil, &blk)
132
- val = parent ? parent.walk_up(val, &blk) : val
133
- blk.call(self, val)
134
- end
89
+ def sibling(name)
90
+ parent && parent.find(name)
91
+ end
135
92
 
136
- # Walk the entire tree, top to bottom.
137
- #
138
- def walk_tree(val = nil, &blk)
139
- val = blk.call(self, val)
140
- children.each do |child|
141
- val = child.walk_tree(val, &blk)
93
+ def siblings
94
+ parent && parent.children
142
95
  end
143
96
 
144
- val
145
- end
97
+ def find(path)
98
+ return self if path.nil? || path.empty?
146
99
 
147
- #
148
- # Reading from filesystem
149
- #
100
+ # remove duplicate slashes
101
+ path.gsub!(%r{/+}, "/")
150
102
 
151
- def reload!
152
- @body = nil
153
- @data = nil
154
- @children = []
155
- @paths = {}
103
+ case path
104
+ when %r{^\./?} then
105
+ parent ? parent.find($') : root.find($')
106
+ when %r{^/} then
107
+ root.find($')
108
+ when %r{^([^/]+)/?} then
109
+ child = find_child($1)
110
+ $'.empty? ? child : child.find($')
111
+ end
112
+ end
156
113
 
157
- load_from_filesystem! if @fs_path
158
- end
114
+ # Walk the tree up, invoking the passed block for every node
115
+ # found on the way, passing the node as its only argument.
116
+ #
117
+ def walk_up(val = nil, &blk)
118
+ val = blk.call(self, val)
119
+ parent ? parent.walk_up(val, &blk) : val
120
+ end
159
121
 
160
- def stage!
161
- # First of all, we want to make sure all nodes have their
162
- # available extensions loaded.
122
+ # Walk the graph from the root to this node. Just like walk_up,
123
+ # except the block will be called on higher level nodes first.
163
124
  #
164
- walk_tree do |node|
165
- node.load_extension! unless node.name == "_node"
125
+ def walk_down(val = nil, &blk)
126
+ val = parent ? parent.walk_up(val, &blk) : val
127
+ blk.call(self, val)
166
128
  end
167
129
 
168
- # Now do another pass, prerendering stuff where necessary,
169
- # extracting data, registering URLs to be exported, etc.
130
+ # Walk the entire tree, top to bottom.
170
131
  #
171
- walk_tree do |node|
172
- node.render_body! if node.should_prerender?
173
- node.register_url! if node.should_publish?
132
+ def walk_tree(val = nil, &blk)
133
+ val = blk.call(self, val)
134
+ children.each do |child|
135
+ val = child.walk_tree(val, &blk)
136
+ end
137
+
138
+ val
174
139
  end
175
140
  end
176
141
 
177
- def should_prerender?
178
- !folder? &&
179
- (["json", "yml", "yaml", "rb", "toml"] & filters).any?
180
- end
142
+ concerning :Reading do
143
+ def reload!
144
+ @body = nil
145
+ @data = nil
146
+ @children = []
147
+ @paths = {}
181
148
 
182
- def load_from_filesystem!
183
- if @fs_path
184
- if ::File.directory?(fs_path)
185
- Dir[::File.join(fs_path, "*")].each do |entry|
186
- name = ::File.basename(entry)
187
- Flutterby::Node.new(name, parent: self, fs_path: entry)
149
+ load_from_filesystem! if @fs_path
150
+ end
151
+
152
+ def load_from_filesystem!
153
+ if @fs_path
154
+ if ::File.directory?(fs_path)
155
+ Dir[::File.join(fs_path, "*")].each do |entry|
156
+ name = ::File.basename(entry)
157
+ Flutterby::Node.new(name, parent: self, fs_path: entry)
158
+ end
159
+ else
160
+ @source = ::File.read(fs_path)
188
161
  end
189
- else
190
- @source = ::File.read(fs_path)
191
162
  end
192
163
  end
193
164
  end
194
165
 
195
- def extract_data!
196
- @data ||= {}
197
-
198
- # Extract date from name
199
- if name =~ %r{^(\d\d\d\d\-\d\d?\-\d\d?)\-}
200
- @data['date'] = Date.parse($1)
166
+ concerning :Data do
167
+ def data
168
+ extract_data! if @data.nil?
169
+ @data
201
170
  end
202
171
 
203
- # Read remaining data from frontmatter. Data in frontmatter
204
- # will always have precedence!
205
- parse_frontmatter!
172
+ def extract_data!
173
+ @data ||= {}
206
174
 
207
- # Do some extra processing depending on extension
208
- meth = "read_#{ext}!"
209
- send(meth) if respond_to?(meth)
210
- end
175
+ # Extract date from name
176
+ if name =~ %r{^(\d\d\d\d\-\d\d?\-\d\d?)\-}
177
+ @data['date'] = Date.parse($1)
178
+ end
211
179
 
212
- def load_extension!
213
- if extension = sibling("_node.rb")
214
- instance_eval(extension.body)
180
+ # Read remaining data from frontmatter. Data in frontmatter
181
+ # will always have precedence!
182
+ parse_frontmatter!
183
+
184
+ # Do some extra processing depending on extension
185
+ meth = "read_#{ext}!"
186
+ send(meth) if respond_to?(meth)
215
187
  end
216
- end
217
188
 
218
- #
219
- # Rendering
220
- #
189
+ def parse_frontmatter!
190
+ @data || {}
221
191
 
222
- def view
223
- @view ||= View.for(self)
224
- end
192
+ if @source
193
+ # YAML Front Matter
194
+ if @source.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
195
+ @data.merge! YAML.load($1)
196
+ end
225
197
 
226
- def render_body!
227
- time = Benchmark.realtime do
228
- Filters.apply!(self)
198
+ # TOML Front Matter
199
+ if @source.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
200
+ @data.merge! TOML.parse($1)
201
+ end
202
+ end
229
203
  end
230
204
 
231
- logger.info "Rendered #{url} in #{sprintf "%.1f", time * 1000}ms"
232
- end
205
+ def read_json!
206
+ @data.merge!(JSON.parse(body))
207
+ end
233
208
 
234
- def body
235
- if @body.nil?
236
- data # make sure data is lazy-loaded
237
- render_body!
209
+ def read_yaml!
210
+ @data.merge!(YAML.load(body))
238
211
  end
239
212
 
240
- @body
241
- end
213
+ def read_yml!
214
+ read_yaml!
215
+ end
242
216
 
243
- def data
244
- extract_data! if @data.nil?
245
- @data
217
+ def read_toml!
218
+ @data.merge!(TOML.parse(body))
219
+ end
246
220
  end
247
221
 
248
- def render(opts = {})
249
- layout = opts[:layout]
250
- view.opts.merge!(opts)
251
- (layout && apply_layout?) ? apply_layout(body) : body
252
- end
222
+ concerning :Staging do
223
+ def stage!
224
+ # First of all, we want to make sure all nodes have their
225
+ # available extensions loaded.
226
+ #
227
+ walk_tree do |node|
228
+ node.load_extension! unless node.name == "_node"
229
+ end
253
230
 
254
- def apply_layout(input)
255
- walk_up(input) do |node, current|
256
- if layout = node.sibling("_layout")
257
- tilt = Flutterby::Filters.tilt(layout.ext, layout.source)
258
- tilt.render(view) { current }.html_safe
259
- else
260
- current
231
+ # Now do another pass, prerendering stuff where necessary,
232
+ # extracting data, registering URLs to be exported, etc.
233
+ #
234
+ walk_tree do |node|
235
+ node.render_body! if node.should_prerender?
236
+ node.register_url! if node.should_publish?
261
237
  end
262
238
  end
263
- end
264
239
 
265
- def apply_layout?
266
- page?
267
- end
240
+ def load_extension!
241
+ if extension = sibling("_node.rb")
242
+ instance_eval(extension.body)
243
+ end
244
+ end
268
245
 
246
+ def should_prerender?
247
+ !folder? &&
248
+ (["json", "yml", "yaml", "rb", "toml"] & filters).any?
249
+ end
250
+ end
269
251
 
270
252
 
253
+ concerning :Rendering do
254
+ def view
255
+ @view ||= View.for(self)
256
+ end
271
257
 
272
- #
273
- # Front Matter Parsing
274
- #
258
+ def render_body!
259
+ time = Benchmark.realtime do
260
+ Filters.apply!(self)
261
+ end
275
262
 
276
- def parse_frontmatter!
277
- @data || {}
263
+ logger.info "Rendered #{url} in #{sprintf "%.1f", time * 1000}ms"
264
+ end
278
265
 
279
- if @source
280
- # YAML Front Matter
281
- if @source.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
282
- @data.merge! YAML.load($1)
266
+ def body
267
+ if @body.nil?
268
+ data # make sure data is lazy-loaded
269
+ render_body!
283
270
  end
284
271
 
285
- # TOML Front Matter
286
- if @source.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
287
- @data.merge! TOML.parse($1)
272
+ @body
273
+ end
274
+
275
+ def render(opts = {})
276
+ layout = opts[:layout]
277
+ view.opts.merge!(opts)
278
+ (layout && apply_layout?) ? apply_layout(body) : body
279
+ end
280
+
281
+ def apply_layout(input)
282
+ walk_up(input) do |node, current|
283
+ if layout = node.sibling("_layout")
284
+ tilt = Flutterby::Filters.tilt(layout.ext, layout.source)
285
+ tilt.render(view) { current }.html_safe
286
+ else
287
+ current
288
+ end
288
289
  end
289
290
  end
290
- end
291
291
 
292
- def read_json!
293
- @data.merge!(JSON.parse(body))
292
+ def apply_layout?
293
+ page?
294
+ end
294
295
  end
295
296
 
296
- def read_yaml!
297
- @data.merge!(YAML.load(body))
298
- end
299
297
 
300
- def read_yml!
301
- read_yaml!
302
- end
303
298
 
304
- def read_toml!
305
- @data.merge!(TOML.parse(body))
306
- end
307
299
 
308
300
 
309
301
  #
@@ -1,3 +1,3 @@
1
1
  module Flutterby
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -35,6 +35,32 @@ module Flutterby
35
35
  node.siblings(*args)
36
36
  end
37
37
 
38
+ def tag(name, attributes)
39
+ ActiveSupport::SafeBuffer.new.tap do |output|
40
+ attributes_str = attributes.keys.sort.map do |k|
41
+ %{#{h k}="#{h attributes[k]}"}
42
+ end.join(" ")
43
+
44
+ opening_tag = "#{h name.downcase} #{attributes_str}".strip
45
+ output << "<#{opening_tag}>".html_safe
46
+ output << yield if block_given?
47
+ output << "</#{h name}>".html_safe
48
+ end
49
+ end
50
+
51
+ def link_to(text, target, attrs = {})
52
+ href = case target
53
+ when Flutterby::Node then target.url
54
+ else target.to_s
55
+ end
56
+
57
+ tag(:a, attrs.merge(href: href)) { text }
58
+ end
59
+
60
+ def debug(obj)
61
+ tag(:pre, class: "debug") { h obj.to_yaml }
62
+ end
63
+
38
64
  class << self
39
65
  # Factory method that returns a newly created view for the given node.
40
66
  # It also makes sure all available _view.rb extensions are loaded.
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  source "https://rubygems.org"
3
3
 
4
- gem "flutterby", "~> 0.3.0"
4
+ gem "flutterby", "~> <%= Flutterby::VERSION %>"
@@ -17,4 +17,4 @@ html
17
17
  = yield
18
18
 
19
19
  footer role="main"
20
- = config["site"]["description"]
20
+ == config["site"]["description"]
@@ -2,5 +2,4 @@ ul.post-list
2
2
  - for post in blog_posts
3
3
  li
4
4
  .post-meta = date_format post.date, "%B %e, %Y"
5
-
6
- a href=post.url = post.title
5
+ = link_to post.title, post
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Welcome to Flutterby!
3
+ date: <%= Date.today.to_s %>
3
4
  ---
4
5
 
5
6
 
@@ -1,6 +1,6 @@
1
1
  h1 = config["site"]["title"]
2
2
 
3
- p This is my new website! <a href="/about.html">Find out more</a>.
3
+ p This is my new website! #{link_to "Find out more", "/about.html"}.
4
4
 
5
5
  h3 Latest Posts:
6
6
  == render("/blog/_list")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flutterby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hendrik Mans
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-15 00:00:00.000000000 Z
11
+ date: 2017-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -364,18 +364,18 @@ files:
364
364
  - lib/flutterby/version.rb
365
365
  - lib/flutterby/view.rb
366
366
  - lib/templates/new_project/.gitignore
367
- - lib/templates/new_project/Gemfile
367
+ - lib/templates/new_project/Gemfile.tt
368
368
  - lib/templates/new_project/README.md
369
369
  - lib/templates/new_project/bin/flutterby
370
370
  - lib/templates/new_project/site/_config.toml
371
371
  - lib/templates/new_project/site/_layout.slim
372
372
  - lib/templates/new_project/site/_view.rb
373
373
  - lib/templates/new_project/site/about.html.md
374
- - lib/templates/new_project/site/blog/2017-01-01-hello-world.html.md
375
374
  - lib/templates/new_project/site/blog/_layout.slim
376
375
  - lib/templates/new_project/site/blog/_list.html.slim
377
376
  - lib/templates/new_project/site/blog/_node.rb
378
377
  - lib/templates/new_project/site/blog/_view.rb
378
+ - lib/templates/new_project/site/blog/hello-world.html.md.tt
379
379
  - lib/templates/new_project/site/css/styles.css.scss
380
380
  - lib/templates/new_project/site/index.html.slim
381
381
  - lib/templates/new_project/site/js/app.js