flutterby 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/.yardopts +2 -0
- data/CHANGES.md +13 -0
- data/README.md +3 -2
- data/bin/yard +17 -0
- data/bin/yardoc +17 -0
- data/bin/yri +17 -0
- data/flutterby.gemspec +1 -0
- data/lib/flutterby.rb +2 -0
- data/lib/flutterby/cli.rb +12 -6
- data/lib/flutterby/dotaccess.rb +31 -0
- data/lib/flutterby/exporter.rb +15 -13
- data/lib/flutterby/filters.rb +15 -15
- data/lib/flutterby/node.rb +205 -150
- data/lib/flutterby/node_extension.rb +23 -0
- data/lib/flutterby/server.rb +9 -8
- data/lib/flutterby/tree_walker.rb +37 -0
- data/lib/flutterby/version.rb +1 -1
- data/lib/flutterby/view.rb +51 -8
- data/lib/templates/new_project/site/_config.yaml +9 -0
- data/lib/templates/new_project/site/_layout.slim +3 -2
- data/lib/templates/new_project/site/blog/_init.rb +11 -0
- data/lib/templates/new_project/site/blog/_layout.slim +1 -1
- data/lib/templates/new_project/site/blog/hello-world.html.md.tt +1 -1
- data/lib/templates/new_project/site/index.html.slim +1 -1
- metadata +25 -4
- data/lib/templates/new_project/site/_config.toml +0 -10
- data/lib/templates/new_project/site/blog/_node.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 679b8fba9c9fda2c5e70df5bb73a16903be5181f
|
4
|
+
data.tar.gz: 5a27688b1713d0bd8bb49695afcb1bb9272682e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b24fcfd4c696520de83fcc2f6a0318f7e3895bf558bdc30145ccf8eca1af57845fca6c393ceac928edcfa3afaf5f99409324d9027269c88a89fd698d6512c35c
|
7
|
+
data.tar.gz: 8a2827f70bc5484a202d9f147e7c0cb0ba04ee3e95106041ceb8439e014321b01474a9273e3d2bcbbcba740eed03263c4d5b86bdb848a453cf13602647da2edb
|
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/CHANGES.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Version History
|
2
2
|
|
3
|
+
### 0.5.0 (2017-01-24)
|
4
|
+
|
5
|
+
- **NEW:** Nodes have two new attributes, `prefix` and `slug`, which are automatically generated from the node's name. If the name starts with a combination of decimals and dashes, these will become the `prefix`, and the remainder auf the name the `suffix`. For example, a name of `123-introduction` will result in a prefix of `123` and a slug of `introduction`. As before, a prefix that looks like a date (eg. `2017-04-01-introduction`) will automatically be parsed into `data[:date]`.
|
6
|
+
- **NEW:** When nodes are being spawned, their names will be changed to their slugs by default (ie. any prefix contained in the original name will be removed.) For example, a `123-foo.html.md` will be exported as just `foo.html`.
|
7
|
+
- **NEW:** Nodes now have first-class support of a node title through the new `title` attribute. This will either use `data[:title]`, when available, or generate a title from `slug` (eg. a node named `hello-world.html.md` will automatically have a title of `Hello World`.)
|
8
|
+
- **NEW:** You can now also access a node's data using a convenient dot syntax; eg. `node.data.foo.bar` will return `node.data[:foo][:bar]`. If you're on Ruby 2.3 or newer, this allows you to use the safe navigation operator; eg. `data.foo&.bar`.
|
9
|
+
- **BREAKING CHANGE:** The `_node.rb` mechanism is gone. In its stead, you can now add `_init.rb` files that will be evaluated automatically; those can use the new `extend_siblings` and `extend_parent` convenience methods to extend all available siblings (or the parent) with the specified module or block.
|
10
|
+
- **NEW:** These node extensions can now supply an `on_setup` block that will be executed after the tree has been fully spawned. You can use these setup blocks to further modify the tree.
|
11
|
+
- **NEW:** The `flutterby build` and `flutterby serve` CLI commands now provide additional debug output when started with the `--debug` option.
|
12
|
+
- **NEW:** Added `Node#create` as a convenience method for creating new child nodes below a given node.
|
13
|
+
- **CHANGE:** Some massive refactoring, the primary intent being to perform the rendering of nodes in a thread-safe manner.
|
14
|
+
|
15
|
+
|
3
16
|
### 0.4.0 (2017-01-21)
|
4
17
|
|
5
18
|
- **NEW:** Flutterby views now have a `tag` helper method available that can generate HTML tags programatically.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Flutterby
|
1
|
+
# Flutterby 🦋
|
2
2
|
|
3
3
|
### A flexible, Ruby-powered static site generator.
|
4
4
|
|
@@ -17,8 +17,9 @@
|
|
17
17
|
|
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
|
+
- [Code Reference Documentation](http://www.rubydoc.info/github/hmans/flutterby)
|
20
21
|
- [Version History](https://github.com/hmans/flutterby/blob/master/CHANGES.md)
|
21
|
-
- [Roadmap](https://github.com/hmans/flutterby/
|
22
|
+
- [Issues/Roadmap](https://github.com/hmans/flutterby/issues)
|
22
23
|
- [Sites built with Flutterby](https://github.com/hmans/flutterby/wiki/Sites-built-with-Flutterby) (add yours!)
|
23
24
|
|
24
25
|
|
data/bin/yard
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'yard' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("yard", "yard")
|
data/bin/yardoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'yardoc' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("yard", "yardoc")
|
data/bin/yri
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'yri' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("yard", "yri")
|
data/flutterby.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency 'awesome_print', '~> 0'
|
31
31
|
spec.add_development_dependency 'gem-release', '~> 0'
|
32
32
|
spec.add_development_dependency 'pry', '~> 0.10'
|
33
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
33
34
|
|
34
35
|
spec.add_dependency 'erubis', '~> 2.7'
|
35
36
|
spec.add_dependency 'erubis-auto', '~> 1.0'
|
data/lib/flutterby.rb
CHANGED
data/lib/flutterby/cli.rb
CHANGED
@@ -21,10 +21,13 @@ module Flutterby
|
|
21
21
|
end
|
22
22
|
|
23
23
|
desc "build", "Build your static site"
|
24
|
-
option :in, default: "./site/", aliases: [
|
25
|
-
option :out, default: "./_build/", aliases: [
|
24
|
+
option :in, default: "./site/", aliases: ["-i"]
|
25
|
+
option :out, default: "./_build/", aliases: ["-o"]
|
26
|
+
option :debug, default: false, aliases: ["-d"], type: :boolean
|
26
27
|
|
27
28
|
def build
|
29
|
+
Flutterby.logger.level = options.debug ? Logger::DEBUG : Logger::INFO
|
30
|
+
|
28
31
|
# Simplify logger output
|
29
32
|
Flutterby.logger.formatter = proc do |severity, datetime, progname, msg|
|
30
33
|
" • #{msg}\n"
|
@@ -49,10 +52,13 @@ module Flutterby
|
|
49
52
|
|
50
53
|
|
51
54
|
desc "serve", "Serve your site locally"
|
52
|
-
option :in, default: "./site/", aliases: [
|
53
|
-
option :port, default: 4004, aliases: [
|
55
|
+
option :in, default: "./site/", aliases: ["-i"]
|
56
|
+
option :port, default: 4004, aliases: ["-p"], type: :numeric
|
57
|
+
option :debug, default: false, aliases: ["-d"], type: :boolean
|
54
58
|
|
55
59
|
def serve
|
60
|
+
Flutterby.logger.level = options.debug ? Logger::DEBUG : Logger::INFO
|
61
|
+
|
56
62
|
say_hi
|
57
63
|
|
58
64
|
say color("📚 Importing site...", :bold)
|
@@ -61,8 +67,8 @@ module Flutterby
|
|
61
67
|
say color("🌲 Read #{root.tree_size} nodes.", :green, :bold)
|
62
68
|
|
63
69
|
say color("🌤 Serving your Flutterby site on http://localhost:#{options.port} - enjoy! \\o/", :bold)
|
64
|
-
server = Flutterby::Server.new(root
|
65
|
-
server.run!
|
70
|
+
server = Flutterby::Server.new(root)
|
71
|
+
server.run!(port: options.port)
|
66
72
|
end
|
67
73
|
|
68
74
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Dotaccess
|
2
|
+
class Proxy
|
3
|
+
def initialize(hash)
|
4
|
+
@hash = hash
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(meth, *args)
|
8
|
+
if @hash.respond_to?(meth)
|
9
|
+
@hash.send(meth, *args)
|
10
|
+
elsif meth =~ %r{\A(.+)=\Z}
|
11
|
+
@hash[$1] = args.first
|
12
|
+
elsif v = (@hash[meth] || @hash[meth.to_s])
|
13
|
+
v.is_a?(Hash) ? Proxy.new(v) : v
|
14
|
+
else
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](k)
|
20
|
+
@hash[k]
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(o)
|
24
|
+
@hash == o
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.[](hash)
|
29
|
+
Proxy.new(hash)
|
30
|
+
end
|
31
|
+
end
|
data/lib/flutterby/exporter.rb
CHANGED
@@ -5,25 +5,27 @@ module Flutterby
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def export!(into:)
|
8
|
-
@root
|
9
|
-
|
10
|
-
|
8
|
+
export_node(@root, into: into)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def export_node(node, into:)
|
14
|
+
return unless node.should_publish?
|
11
15
|
|
12
|
-
|
13
|
-
# Make sure directory exists
|
14
|
-
FileUtils.mkdir_p(::File.dirname(path))
|
16
|
+
path = ::File.expand_path(::File.join(into, node.full_name))
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
if node.file?
|
19
|
+
::File.write(path, node.render(layout: true))
|
20
|
+
logger.info "Exported #{node.url}"
|
21
|
+
else
|
22
|
+
FileUtils.mkdir_p(path)
|
23
|
+
node.children.each do |child|
|
24
|
+
export_node(child, into: path)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
29
|
def logger
|
28
30
|
@logger ||= Flutterby.logger
|
29
31
|
end
|
data/lib/flutterby/filters.rb
CHANGED
@@ -8,19 +8,19 @@ require 'flutterby/markdown_formatter'
|
|
8
8
|
|
9
9
|
module Flutterby
|
10
10
|
module Filters
|
11
|
-
def self.apply!(
|
12
|
-
|
11
|
+
def self.apply!(view)
|
12
|
+
view._body = view.source.try(:html_safe)
|
13
13
|
|
14
14
|
# Apply all filters
|
15
|
-
node.filters.each do |filter|
|
15
|
+
view.node.filters.each do |filter|
|
16
16
|
meth = "process_#{filter}!"
|
17
17
|
|
18
18
|
if Filters.respond_to?(meth)
|
19
|
-
Filters.send(meth,
|
20
|
-
elsif template = tilt(filter,
|
21
|
-
|
19
|
+
Filters.send(meth, view)
|
20
|
+
elsif template = tilt(filter, view._body)
|
21
|
+
view._body = template.render(view).html_safe
|
22
22
|
else
|
23
|
-
Flutterby.logger.warn "Unsupported filter '#{filter}' for #{node.url}"
|
23
|
+
Flutterby.logger.warn "Unsupported filter '#{filter}' for #{view.node.url}"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -43,23 +43,23 @@ module Flutterby
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
Flutterby::Filters.add("rb") do |
|
47
|
-
|
46
|
+
Flutterby::Filters.add("rb") do |view|
|
47
|
+
view._body = view.instance_eval(view._body)
|
48
48
|
end
|
49
49
|
|
50
|
-
Flutterby::Filters.add(["md", "markdown"]) do |
|
51
|
-
|
50
|
+
Flutterby::Filters.add(["md", "markdown"]) do |view|
|
51
|
+
view._body = Flutterby::MarkdownFormatter.new(view._body).complete.to_s.html_safe
|
52
52
|
end
|
53
53
|
|
54
|
-
Flutterby::Filters.add("scss") do |
|
54
|
+
Flutterby::Filters.add("scss") do |view|
|
55
55
|
sass_options = {
|
56
56
|
syntax: :scss,
|
57
57
|
load_paths: []
|
58
58
|
}
|
59
59
|
|
60
|
-
if node.fs_path
|
61
|
-
sass_options[:load_paths] << File.dirname(node.fs_path)
|
60
|
+
if view.node.fs_path
|
61
|
+
sass_options[:load_paths] << File.dirname(view.node.fs_path)
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
view._body = Sass::Engine.new(view._body, sass_options).render
|
65
65
|
end
|
data/lib/flutterby/node.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'flutterby/node_extension'
|
2
2
|
|
3
3
|
module Flutterby
|
4
4
|
class Node
|
5
5
|
attr_accessor :name, :ext, :source
|
6
|
-
|
7
|
-
attr_reader :
|
6
|
+
attr_reader :filters, :parent, :fs_path, :children
|
7
|
+
attr_reader :prefix, :slug
|
8
|
+
attr_reader :_setup_procs
|
8
9
|
|
9
10
|
def initialize(name, parent: nil, fs_path: nil, source: nil)
|
10
11
|
@fs_path = fs_path ? ::File.expand_path(fs_path) : nil
|
11
12
|
@source = source
|
13
|
+
@_setup_procs = []
|
12
14
|
|
13
15
|
# Extract name, extension, and filters from given name
|
14
16
|
parts = name.split(".")
|
@@ -24,21 +26,66 @@ module Flutterby
|
|
24
26
|
reload!
|
25
27
|
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
module Paths
|
30
|
+
# Returns the node's URL.
|
31
|
+
#
|
32
|
+
def url
|
33
|
+
::File.join(parent ? parent.url : "/", full_name)
|
32
34
|
end
|
35
|
+
end
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
include Paths
|
38
|
+
|
39
|
+
|
40
|
+
module Tree
|
41
|
+
# Returns the tree's root node.
|
42
|
+
#
|
43
|
+
def root
|
44
|
+
parent ? parent.root : self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns true if this node is also the tree's root node.
|
48
|
+
#
|
49
|
+
def root?
|
50
|
+
root == self
|
51
|
+
end
|
52
|
+
|
53
|
+
def sibling(name)
|
54
|
+
parent && parent.find(name)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns this node's siblings (ie. other nodes within the
|
58
|
+
# same folder node.)
|
59
|
+
#
|
60
|
+
def siblings
|
61
|
+
parent && (parent.children - [self])
|
62
|
+
end
|
63
|
+
|
64
|
+
# Among this node's children, find a node by its name. If the
|
65
|
+
# name passed as an argument includes a dot, the name will match against
|
66
|
+
# the full name of the children; otherwise, just the base name.
|
67
|
+
#
|
68
|
+
# Examples:
|
69
|
+
#
|
70
|
+
# # returns the first child called "index"
|
71
|
+
# find_child("index")
|
72
|
+
#
|
73
|
+
# # returns the child called "index" with extension "html"
|
74
|
+
# find_child("index.html")
|
75
|
+
#
|
76
|
+
def find_child(name, opts = {})
|
77
|
+
name_attr = name.include?(".") ? "full_name" : "name"
|
78
|
+
|
79
|
+
@children.find do |c|
|
80
|
+
(c.should_publish? || !opts[:public_only]) &&
|
81
|
+
(c.send(name_attr) == name)
|
39
82
|
end
|
40
83
|
end
|
41
84
|
|
85
|
+
def emit_child(name)
|
86
|
+
# Override this to dynamically create child nodes.
|
87
|
+
end
|
88
|
+
|
42
89
|
def tree_size
|
43
90
|
children.inject(children.length) do |count, child|
|
44
91
|
count + child.tree_size
|
@@ -46,109 +93,89 @@ module Flutterby
|
|
46
93
|
end
|
47
94
|
|
48
95
|
def parent=(new_parent)
|
96
|
+
# Remove from previous parent
|
49
97
|
if @parent
|
50
98
|
@parent.children.delete(self)
|
51
99
|
end
|
52
100
|
|
101
|
+
# Assign new parent (it may be nil)
|
53
102
|
@parent = new_parent
|
54
103
|
|
55
|
-
|
104
|
+
# Notify new parent
|
105
|
+
if @parent
|
106
|
+
@parent.children << self
|
107
|
+
end
|
56
108
|
end
|
57
109
|
|
58
110
|
# Returns all children that will compile to a HTML page.
|
59
111
|
#
|
60
112
|
def pages
|
61
|
-
children.select { |c| c.
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
concerning :Paths do
|
66
|
-
def path
|
67
|
-
parent ? ::File.join(parent.path, full_name) : full_name
|
68
|
-
end
|
69
|
-
|
70
|
-
def url
|
71
|
-
::File.join(parent ? parent.url : "/", full_name)
|
72
|
-
end
|
73
|
-
|
74
|
-
def full_fs_path(base:)
|
75
|
-
::File.expand_path(::File.join(base, full_name))
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
concerning :Tree do
|
81
|
-
def root
|
82
|
-
parent ? parent.root : self
|
83
|
-
end
|
84
|
-
|
85
|
-
def root?
|
86
|
-
root == self
|
87
|
-
end
|
88
|
-
|
89
|
-
def sibling(name)
|
90
|
-
parent && parent.find(name)
|
113
|
+
children.select { |c| c.page? }
|
91
114
|
end
|
92
115
|
|
93
|
-
|
94
|
-
|
116
|
+
# Creates a new node, using the specified arguments, as a child
|
117
|
+
# of this node.
|
118
|
+
#
|
119
|
+
def create(name, **args)
|
120
|
+
args[:parent] = self
|
121
|
+
Node.new(name.to_s, **args)
|
95
122
|
end
|
96
123
|
|
97
|
-
def find(path)
|
98
|
-
|
124
|
+
def find(path, opts = {})
|
125
|
+
path = path.to_s
|
126
|
+
return self if path.empty?
|
99
127
|
|
100
128
|
# remove duplicate slashes
|
101
|
-
path.gsub
|
129
|
+
path = path.gsub(%r{/+}, "/")
|
102
130
|
|
103
131
|
case path
|
132
|
+
# ./foo/...
|
104
133
|
when %r{^\./?} then
|
105
|
-
parent ? parent.find($') : root.find($')
|
134
|
+
parent ? parent.find($', opts) : root.find($', opts)
|
135
|
+
|
136
|
+
# /foo/...
|
106
137
|
when %r{^/} then
|
107
|
-
root.find($')
|
138
|
+
root.find($', opts)
|
139
|
+
|
140
|
+
# foo/...
|
108
141
|
when %r{^([^/]+)/?} then
|
109
|
-
child
|
110
|
-
|
142
|
+
# Use the next path part to find a child by that name.
|
143
|
+
# If no child can't be found, try to emit a child, but
|
144
|
+
# not if the requested name starts with an underscore.
|
145
|
+
if child = find_child($1, opts) || (emit_child($1) unless $1.start_with?("_"))
|
146
|
+
# Depending on the tail of the requested find expression,
|
147
|
+
# either return the found node, or ask it to find the tail.
|
148
|
+
$'.empty? ? child : child.find($', opts)
|
149
|
+
end
|
111
150
|
end
|
112
151
|
end
|
152
|
+
end
|
113
153
|
|
114
|
-
|
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
|
154
|
+
include Tree
|
121
155
|
|
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.
|
124
|
-
#
|
125
|
-
def walk_down(val = nil, &blk)
|
126
|
-
val = parent ? parent.walk_up(val, &blk) : val
|
127
|
-
blk.call(self, val)
|
128
|
-
end
|
129
156
|
|
130
|
-
|
157
|
+
module Reading
|
158
|
+
# (Re-)loads the node from the filesystem, if it's a filesystem based
|
159
|
+
# node.
|
131
160
|
#
|
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
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
concerning :Reading do
|
143
161
|
def reload!
|
144
|
-
@body = nil
|
145
162
|
@data = nil
|
163
|
+
@data_proxy = nil
|
164
|
+
@prefix = nil
|
165
|
+
@slug = nil
|
146
166
|
@children = []
|
147
|
-
@paths = {}
|
148
167
|
|
149
168
|
load_from_filesystem! if @fs_path
|
169
|
+
|
170
|
+
extract_data!
|
171
|
+
end
|
172
|
+
|
173
|
+
def data
|
174
|
+
@data_proxy ||= Dotaccess[@data]
|
150
175
|
end
|
151
176
|
|
177
|
+
private
|
178
|
+
|
152
179
|
def load_from_filesystem!
|
153
180
|
if @fs_path
|
154
181
|
if ::File.directory?(fs_path)
|
@@ -161,32 +188,41 @@ module Flutterby
|
|
161
188
|
end
|
162
189
|
end
|
163
190
|
end
|
164
|
-
end
|
165
191
|
|
166
|
-
|
167
|
-
def data
|
168
|
-
extract_data! if @data.nil?
|
169
|
-
@data
|
170
|
-
end
|
192
|
+
private
|
171
193
|
|
172
194
|
def extract_data!
|
173
|
-
@data ||= {}
|
195
|
+
@data ||= {}.with_indifferent_access
|
196
|
+
|
197
|
+
# Extract prefix and slug
|
198
|
+
if name =~ %r{\A([\d-]+)-(.+)\Z}
|
199
|
+
@prefix = $1
|
200
|
+
@slug = $2
|
201
|
+
else
|
202
|
+
@slug = name
|
203
|
+
end
|
174
204
|
|
175
|
-
#
|
176
|
-
|
205
|
+
# Change this node's name to the slug. This may be made optional
|
206
|
+
# in the future.
|
207
|
+
@name = @slug
|
208
|
+
|
209
|
+
# Extract date from prefix if possible
|
210
|
+
if prefix =~ %r{\A(\d\d\d\d\-\d\d?\-\d\d?)\Z}
|
177
211
|
@data['date'] = Date.parse($1)
|
178
212
|
end
|
179
213
|
|
180
214
|
# Read remaining data from frontmatter. Data in frontmatter
|
181
215
|
# will always have precedence!
|
182
|
-
|
216
|
+
extract_frontmatter!
|
183
217
|
|
184
|
-
# Do some extra processing depending on extension
|
218
|
+
# Do some extra processing depending on extension. This essentially
|
219
|
+
# means that your .json etc. files will be rendered at least once at
|
220
|
+
# bootup.
|
185
221
|
meth = "read_#{ext}!"
|
186
|
-
send(meth) if respond_to?(meth)
|
222
|
+
send(meth) if respond_to?(meth, true)
|
187
223
|
end
|
188
224
|
|
189
|
-
def
|
225
|
+
def extract_frontmatter!
|
190
226
|
@data || {}
|
191
227
|
|
192
228
|
if @source
|
@@ -203,11 +239,11 @@ module Flutterby
|
|
203
239
|
end
|
204
240
|
|
205
241
|
def read_json!
|
206
|
-
@data.merge!(JSON.parse(
|
242
|
+
@data.merge!(JSON.parse(render))
|
207
243
|
end
|
208
244
|
|
209
245
|
def read_yaml!
|
210
|
-
@data.merge!(YAML.load(
|
246
|
+
@data.merge!(YAML.load(render))
|
211
247
|
end
|
212
248
|
|
213
249
|
def read_yml!
|
@@ -215,85 +251,95 @@ module Flutterby
|
|
215
251
|
end
|
216
252
|
|
217
253
|
def read_toml!
|
218
|
-
@data.merge!(TOML.parse(
|
254
|
+
@data.merge!(TOML.parse(render))
|
219
255
|
end
|
220
256
|
end
|
221
257
|
|
222
|
-
|
258
|
+
include Reading
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
module Staging
|
223
263
|
def stage!
|
224
|
-
# First of all, we want to make sure all
|
225
|
-
#
|
264
|
+
# First of all, we want to make sure all initializers
|
265
|
+
# (`_init.rb` files) are executed, starting at the top of the tree.
|
226
266
|
#
|
227
|
-
walk_tree do |node|
|
228
|
-
|
267
|
+
TreeWalker.walk_tree(self) do |node|
|
268
|
+
if node.full_name == "_init.rb"
|
269
|
+
logger.debug "Executing initializer #{node.url}"
|
270
|
+
node.instance_eval(node.render)
|
271
|
+
end
|
229
272
|
end
|
230
273
|
|
231
|
-
#
|
232
|
-
#
|
274
|
+
# In a second pass, walk the tree to invoke any available
|
275
|
+
# setup methods.
|
233
276
|
#
|
234
|
-
walk_tree do |node|
|
235
|
-
node.
|
236
|
-
node.register_url! if node.should_publish?
|
277
|
+
TreeWalker.walk_tree(self) do |node|
|
278
|
+
node.perform_setup!
|
237
279
|
end
|
238
280
|
end
|
239
281
|
|
240
|
-
|
241
|
-
|
242
|
-
|
282
|
+
# Perform setup for this node. The setup step is run after the
|
283
|
+
# tree has been built up completely. It allows you to perform one-time
|
284
|
+
# setup operations that, for example, modify the tree (like sorting blog
|
285
|
+
# posts into date-specific subnodes.)
|
286
|
+
#
|
287
|
+
# Your nodes (or their extensions) may overload this method, but you
|
288
|
+
# may also simply use the `setup { ... }` syntax in a node extension
|
289
|
+
# to define a block of code to be run at setup time.
|
290
|
+
#
|
291
|
+
def perform_setup!
|
292
|
+
_setup_procs.each do |p|
|
293
|
+
instance_exec(&p)
|
243
294
|
end
|
244
295
|
end
|
245
296
|
|
246
|
-
|
247
|
-
|
248
|
-
|
297
|
+
# Extend all of this node's siblings. See {#extend_all}.
|
298
|
+
#
|
299
|
+
def extend_siblings(*mods, &blk)
|
300
|
+
extend_all(siblings, *mods, &blk)
|
249
301
|
end
|
250
|
-
end
|
251
302
|
|
252
|
-
|
253
|
-
|
254
|
-
def
|
255
|
-
|
303
|
+
# Extend this node's parent. See {#extend_all}.
|
304
|
+
#
|
305
|
+
def extend_parent(*mods, &blk)
|
306
|
+
extend_all([parent], *mods, &blk)
|
256
307
|
end
|
257
308
|
|
258
|
-
|
259
|
-
|
260
|
-
|
309
|
+
# Extend all of the specified `nodes` with the specified module(s). If
|
310
|
+
# a block is given, the nodes will be extended with the code found
|
311
|
+
# in the block.
|
312
|
+
#
|
313
|
+
def extend_all(nodes, *mods, &blk)
|
314
|
+
if block_given?
|
315
|
+
mods << NodeExtension.new(&blk)
|
261
316
|
end
|
262
317
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
def body
|
267
|
-
if @body.nil?
|
268
|
-
data # make sure data is lazy-loaded
|
269
|
-
render_body!
|
318
|
+
nodes.each do |n|
|
319
|
+
n.extend(*mods)
|
270
320
|
end
|
271
|
-
|
272
|
-
@body
|
273
321
|
end
|
322
|
+
end
|
274
323
|
|
275
|
-
|
276
|
-
layout = opts[:layout]
|
277
|
-
view.opts.merge!(opts)
|
278
|
-
(layout && apply_layout?) ? apply_layout(body) : body
|
279
|
-
end
|
324
|
+
include Staging
|
280
325
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
current
|
288
|
-
end
|
289
|
-
end
|
326
|
+
|
327
|
+
module Rendering
|
328
|
+
# Returns a freshly created {View} instance for this node.
|
329
|
+
#
|
330
|
+
def view(opts = {})
|
331
|
+
View.for(self, opts)
|
290
332
|
end
|
291
333
|
|
292
|
-
|
293
|
-
|
334
|
+
# Creates a new {View} instance through {#view} and uses it to
|
335
|
+
# render this node. Returns the rendered page as a string.
|
336
|
+
#
|
337
|
+
def render(opts = {})
|
338
|
+
view(opts).render!
|
294
339
|
end
|
295
340
|
end
|
296
341
|
|
342
|
+
include Rendering
|
297
343
|
|
298
344
|
|
299
345
|
|
@@ -302,8 +348,16 @@ module Flutterby
|
|
302
348
|
# Misc
|
303
349
|
#
|
304
350
|
|
351
|
+
# Returns the node's title. If there is a `:title` key in {#data}, its
|
352
|
+
# value will be used; otherwise, as a fallback, it will generate a
|
353
|
+
# human-readable title from {#slug}.
|
354
|
+
#
|
355
|
+
def title
|
356
|
+
data[:title] || slug.try(:titleize)
|
357
|
+
end
|
358
|
+
|
305
359
|
def to_s
|
306
|
-
"<#{self.class} #{self.
|
360
|
+
"<#{self.class} #{self.url}>"
|
307
361
|
end
|
308
362
|
|
309
363
|
def full_name
|
@@ -315,11 +369,11 @@ module Flutterby
|
|
315
369
|
end
|
316
370
|
|
317
371
|
def file?
|
318
|
-
!folder?
|
372
|
+
!folder? && should_publish?
|
319
373
|
end
|
320
374
|
|
321
375
|
def page?
|
322
|
-
|
376
|
+
file? && ext == "html"
|
323
377
|
end
|
324
378
|
|
325
379
|
def should_publish?
|
@@ -330,9 +384,10 @@ module Flutterby
|
|
330
384
|
Flutterby.logger
|
331
385
|
end
|
332
386
|
|
333
|
-
def copy(new_name)
|
387
|
+
def copy(new_name, data = {})
|
334
388
|
dup.tap do |c|
|
335
389
|
c.name = new_name
|
390
|
+
c.data.merge!(data)
|
336
391
|
parent.children << c
|
337
392
|
end
|
338
393
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Flutterby
|
2
|
+
# NodeExtension is a subclass of Module that also provides a convenient
|
3
|
+
# `setup` method for quick creation of initialization code. It's used
|
4
|
+
# to wrap the blocks of code passed to {Node#extend_all} and friends,
|
5
|
+
# but can also be used directly through `NodeExtension.new { ... }`.
|
6
|
+
#
|
7
|
+
class NodeExtension < Module
|
8
|
+
def initialize(*args)
|
9
|
+
@_setup_procs = []
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def extended(base)
|
14
|
+
if @_setup_procs.any?
|
15
|
+
base._setup_procs.append(*@_setup_procs)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_setup(&blk)
|
20
|
+
@_setup_procs << blk
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/flutterby/server.rb
CHANGED
@@ -4,12 +4,11 @@ require 'better_errors'
|
|
4
4
|
|
5
5
|
module Flutterby
|
6
6
|
class Server
|
7
|
-
def initialize(root
|
7
|
+
def initialize(root)
|
8
8
|
@root = root
|
9
|
-
@port = port
|
10
9
|
end
|
11
10
|
|
12
|
-
def run!
|
11
|
+
def run!(port: 4004)
|
13
12
|
# Set up listener
|
14
13
|
listener = Listen.to(@root.fs_path) do |modified, added, removed|
|
15
14
|
# puts "modified absolute path: #{modified}"
|
@@ -40,11 +39,11 @@ module Flutterby
|
|
40
39
|
|
41
40
|
# Go!
|
42
41
|
listener.start
|
43
|
-
server.run app, Port:
|
42
|
+
server.run app, Port: port, Logger: Flutterby.logger
|
44
43
|
end
|
45
44
|
|
46
45
|
def call(env)
|
47
|
-
req
|
46
|
+
req = Rack::Request.new(env)
|
48
47
|
res = Rack::Response.new([], 200, {})
|
49
48
|
|
50
49
|
# Look for target node in path registry
|
@@ -65,9 +64,11 @@ module Flutterby
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def find_node_for_path(path)
|
68
|
-
@root.
|
69
|
-
|
70
|
-
|
67
|
+
if node = @root.find(path, public_only: true)
|
68
|
+
# If the node is a folder, try and find its "index" node.
|
69
|
+
# Otherwise, use the node directly.
|
70
|
+
node.folder? ? node.find('index') : node
|
71
|
+
end
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Flutterby
|
2
|
+
# A helper module with methods to walk across a node tree in various
|
3
|
+
# directions and variations and perform a block of code on each passed node.
|
4
|
+
#
|
5
|
+
module TreeWalker
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# Walk the tree up, invoking the passed block for every node
|
9
|
+
# found on the way, passing the node as its only argument.
|
10
|
+
#
|
11
|
+
def walk_up(node, val = nil, &blk)
|
12
|
+
val = blk.call(node, val)
|
13
|
+
node.parent ? walk_up(node.parent, val, &blk) : val
|
14
|
+
end
|
15
|
+
|
16
|
+
# Walk the graph from the root to the specified node. Just like {#walk_up},
|
17
|
+
# except the block will be called on higher level nodes first.
|
18
|
+
#
|
19
|
+
def walk_down(node, val = nil, &blk)
|
20
|
+
val = node.parent ? walk_up(node.parent, val, &blk) : val
|
21
|
+
blk.call(node, val)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Walk the entire tree, top to bottom, starting with its root, and then
|
25
|
+
# descending into its child layers.
|
26
|
+
#
|
27
|
+
def walk_tree(node, val = nil, &blk)
|
28
|
+
val = blk.call(node, val)
|
29
|
+
|
30
|
+
node.children.each do |child|
|
31
|
+
val = walk_tree(child, val, &blk)
|
32
|
+
end
|
33
|
+
|
34
|
+
val
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/flutterby/version.rb
CHANGED
data/lib/flutterby/view.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
1
3
|
module Flutterby
|
2
4
|
class View
|
3
|
-
attr_reader :node, :opts
|
5
|
+
attr_reader :node, :opts, :source
|
6
|
+
attr_accessor :_body
|
4
7
|
alias_method :page, :node
|
5
8
|
|
6
9
|
# Include ERB::Util from ActiveSupport. This will provide
|
@@ -10,9 +13,41 @@ module Flutterby
|
|
10
13
|
#
|
11
14
|
include ERB::Util
|
12
15
|
|
13
|
-
def initialize(node)
|
16
|
+
def initialize(node, opts = {})
|
14
17
|
@node = node
|
15
|
-
@opts =
|
18
|
+
@opts = opts
|
19
|
+
@source = node.source
|
20
|
+
@_body = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def render!
|
24
|
+
time = Benchmark.realtime do
|
25
|
+
Filters.apply!(self)
|
26
|
+
|
27
|
+
# Apply layouts
|
28
|
+
if opts[:layout] && node.page?
|
29
|
+
@_body = apply_layout!(@_body)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
logger.info "Rendered #{node.url} in #{sprintf "%.1f", time * 1000}ms"
|
34
|
+
|
35
|
+
@_body
|
36
|
+
end
|
37
|
+
|
38
|
+
def apply_layout!(input)
|
39
|
+
TreeWalker.walk_up(node, input) do |node, current|
|
40
|
+
if layout = node.sibling("_layout")
|
41
|
+
tilt = Flutterby::Filters.tilt(layout.ext, layout.source)
|
42
|
+
tilt.render(self) { current }.html_safe
|
43
|
+
else
|
44
|
+
current
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
@_body ||= render!
|
16
51
|
end
|
17
52
|
|
18
53
|
def date_format(date, fmt)
|
@@ -24,7 +59,11 @@ module Flutterby
|
|
24
59
|
end
|
25
60
|
|
26
61
|
def render(expr, *args)
|
27
|
-
|
62
|
+
if expr.is_a?(Node)
|
63
|
+
expr.render(*args)
|
64
|
+
else
|
65
|
+
find(expr).render(*args)
|
66
|
+
end
|
28
67
|
end
|
29
68
|
|
30
69
|
def find(*args)
|
@@ -35,7 +74,7 @@ module Flutterby
|
|
35
74
|
node.siblings(*args)
|
36
75
|
end
|
37
76
|
|
38
|
-
def tag(name, attributes)
|
77
|
+
def tag(name, attributes = {})
|
39
78
|
ActiveSupport::SafeBuffer.new.tap do |output|
|
40
79
|
attributes_str = attributes.keys.sort.map do |k|
|
41
80
|
%{#{h k}="#{h attributes[k]}"}
|
@@ -61,16 +100,20 @@ module Flutterby
|
|
61
100
|
tag(:pre, class: "debug") { h obj.to_yaml }
|
62
101
|
end
|
63
102
|
|
103
|
+
def logger
|
104
|
+
@logger ||= Flutterby.logger
|
105
|
+
end
|
106
|
+
|
64
107
|
class << self
|
65
108
|
# Factory method that returns a newly created view for the given node.
|
66
109
|
# It also makes sure all available _view.rb extensions are loaded.
|
67
110
|
#
|
68
|
-
def for(
|
111
|
+
def for(node, *args)
|
69
112
|
# create a new view instance
|
70
|
-
view = new(
|
113
|
+
view = new(node, *args)
|
71
114
|
|
72
115
|
# walk the tree up to dynamically extend the view
|
73
|
-
|
116
|
+
TreeWalker.walk_down(node) do |e|
|
74
117
|
if view_node = e.sibling("_view.rb")
|
75
118
|
case view_node.ext
|
76
119
|
when "rb" then
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# This is your site's configuration file.
|
2
|
+
|
3
|
+
site:
|
4
|
+
title: My Flutterby Site
|
5
|
+
description: >
|
6
|
+
This is my new <a href="https://github.com/hmans/flutterby">Flutterby</a> Site. I should probably
|
7
|
+
change this description in my site's configuration file,
|
8
|
+
found at ./site/_config.yaml. Or I can just leave it as is.
|
9
|
+
Isn't choice wonderful?
|
@@ -2,7 +2,8 @@ doctype html
|
|
2
2
|
html
|
3
3
|
head
|
4
4
|
meta charset="utf-8"
|
5
|
-
title = config
|
5
|
+
title = config.site.title
|
6
|
+
meta name="viewport" content="width=device-width, initial-scale=1.0"
|
6
7
|
|
7
8
|
// highlight.js for syntax highlighting
|
8
9
|
link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/default.min.css"
|
@@ -17,4 +18,4 @@ html
|
|
17
18
|
= yield
|
18
19
|
|
19
20
|
footer role="main"
|
20
|
-
== config
|
21
|
+
== config.site.description
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# A _init.rb file contains Ruby code that will be executed when
|
2
|
+
# your application boots up. Use it to extend and modify other nodes!
|
3
|
+
#
|
4
|
+
# In this simple example, we're simply adding some convenience methods to
|
5
|
+
# all available blog posts for easier access to specific pieces of data.
|
6
|
+
|
7
|
+
extend_siblings do
|
8
|
+
def date
|
9
|
+
data.date
|
10
|
+
end
|
11
|
+
end
|
@@ -8,7 +8,7 @@ date: <%= Date.today.to_s %>
|
|
8
8
|
|
9
9
|
This sample project is set up as a simple blog, but of course you can do so much more with Flutterby. Just head straight into your project's `site` directory and mix things up. Some files you should look at:
|
10
10
|
|
11
|
-
| `/_config.
|
11
|
+
| `/_config.yaml` | Your site configuration. |
|
12
12
|
| `/css/styles.css.scss` | Your stylesheet. [Sass]-powered, of course! |
|
13
13
|
| `/_layout.slim` | Your global site layout. |
|
14
14
|
| `/posts/_layout.slim` | Your post-specific layout. |
|
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.
|
4
|
+
version: 0.5.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-
|
11
|
+
date: 2017-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0.10'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.9'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.9'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: erubis
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -343,6 +357,7 @@ files:
|
|
343
357
|
- ".gitignore"
|
344
358
|
- ".rspec"
|
345
359
|
- ".travis.yml"
|
360
|
+
- ".yardopts"
|
346
361
|
- CHANGES.md
|
347
362
|
- Gemfile
|
348
363
|
- LICENSE.txt
|
@@ -352,28 +367,34 @@ files:
|
|
352
367
|
- bin/rake
|
353
368
|
- bin/rspec
|
354
369
|
- bin/setup
|
370
|
+
- bin/yard
|
371
|
+
- bin/yardoc
|
372
|
+
- bin/yri
|
355
373
|
- exe/flutterby
|
356
374
|
- flutterby.gemspec
|
357
375
|
- lib/flutterby.rb
|
358
376
|
- lib/flutterby/cli.rb
|
377
|
+
- lib/flutterby/dotaccess.rb
|
359
378
|
- lib/flutterby/exporter.rb
|
360
379
|
- lib/flutterby/filters.rb
|
361
380
|
- lib/flutterby/markdown_formatter.rb
|
362
381
|
- lib/flutterby/node.rb
|
382
|
+
- lib/flutterby/node_extension.rb
|
363
383
|
- lib/flutterby/server.rb
|
384
|
+
- lib/flutterby/tree_walker.rb
|
364
385
|
- lib/flutterby/version.rb
|
365
386
|
- lib/flutterby/view.rb
|
366
387
|
- lib/templates/new_project/.gitignore
|
367
388
|
- lib/templates/new_project/Gemfile.tt
|
368
389
|
- lib/templates/new_project/README.md
|
369
390
|
- lib/templates/new_project/bin/flutterby
|
370
|
-
- lib/templates/new_project/site/_config.
|
391
|
+
- lib/templates/new_project/site/_config.yaml
|
371
392
|
- lib/templates/new_project/site/_layout.slim
|
372
393
|
- lib/templates/new_project/site/_view.rb
|
373
394
|
- lib/templates/new_project/site/about.html.md
|
395
|
+
- lib/templates/new_project/site/blog/_init.rb
|
374
396
|
- lib/templates/new_project/site/blog/_layout.slim
|
375
397
|
- lib/templates/new_project/site/blog/_list.html.slim
|
376
|
-
- lib/templates/new_project/site/blog/_node.rb
|
377
398
|
- lib/templates/new_project/site/blog/_view.rb
|
378
399
|
- lib/templates/new_project/site/blog/hello-world.html.md.tt
|
379
400
|
- lib/templates/new_project/site/css/styles.css.scss
|
@@ -1,10 +0,0 @@
|
|
1
|
-
# This is your site's configuration file.
|
2
|
-
|
3
|
-
[site]
|
4
|
-
title = "My Flutterby Site"
|
5
|
-
description = """
|
6
|
-
This is my new <a href="https://github.com/hmans/flutterby">Flutterby</a> Site. I should probably
|
7
|
-
change this description in my site's configuration file,
|
8
|
-
found at ./site/_config.toml. Or I can just leave it as is.
|
9
|
-
Isn't choice wonderful?
|
10
|
-
"""
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# A _node.rb will be run against all nodes from the same directory -- use it
|
2
|
-
# to enhance the Ruby objects representing these nodes with extra methods
|
3
|
-
# or behavior.
|
4
|
-
#
|
5
|
-
# In this example, we're simply adding some convenience methods for easier
|
6
|
-
# access to specific pieces of data.
|
7
|
-
|
8
|
-
def date
|
9
|
-
data["date"]
|
10
|
-
end
|
11
|
-
|
12
|
-
def title
|
13
|
-
data["title"]
|
14
|
-
end
|