flutterby 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6568ea63c5bdde201dbc5a1b742075e9cdf98353
4
- data.tar.gz: e6b105a6a82e813e8bae5d41c81ff1a61d721c3e
3
+ metadata.gz: 6269342eafe0fdbe1eddad019ecd44ebd5aea360
4
+ data.tar.gz: 6e9c64dda3163516e527b48247546226e943be0f
5
5
  SHA512:
6
- metadata.gz: 59b76bd0e67caa50af779351c25081cc2626e1074c6ebf323bc5a6b5f88d5c9e64850ec68c5beab7f109cbb3672f8f480530c0d7f4a0dc17e05dcb6189aa9817
7
- data.tar.gz: 18de50df6ce8bc75282b8b97f4c010bfae23aab5f053397e4bbb18abea8600bcbc0581f04ac18c3e847f1da0beb3fb0a5e4576041392525723117b3a20a4ea99
6
+ metadata.gz: d850ecf93387945baf0e1d7fdb8cf7368cd474c8c24f2d536a9a7ae6d53b0fa2b6c363a078a3ab561af88c333f66af7feb306a6a297ca337af53d3e44917e05e
7
+ data.tar.gz: 46c17e31c18fbd87c86e5795f15fdd35b3edcccf365d84305e5e828e5228b21022a2a7b4faa55961059bdad3ecf521dd52ee10956aa9d90a3e6b5eb3d9065797
data/README.md CHANGED
@@ -19,6 +19,26 @@ the _experimental_ bit, though. Use with care, if at all!)
19
19
  - Produce a fun screencast to explain what the heck is going on here!
20
20
  - More tests, of course!
21
21
 
22
+ ## How does Flutterby work?
23
+
24
+ A loose collection of notes on how Flutterby actually generates your site -- mostly intended as rubberducking with myself.
25
+
26
+ - Flutterby reads a _source directory_ and writes a static website into a _target directory_. (It can also serve a live version of your site.)
27
+ - Before it writes (or serves) anything, it reads the entire contents from the source directory into a graph of plain old Ruby objects. Each of these objects represents a file (or folder) from your site.
28
+ - Flutterby then walks this tree to write the resulting static site, optionally _applying filters_ first. For example, `index.html.md` will be exported as `index.html` after applying a Markdown filter.
29
+ - These filters can be anything that modifies the Ruby object. Some examples:
30
+ - Rendering Markdown to HTML
31
+ - Parsing and executing ERB, Slim, HAML and other templating engines
32
+ - Processing Sass, CoffeeScript and the likes
33
+ - Leaving the current body intact, but modifying file attributes like the generated file's extension
34
+ - Filters can be chained at any length you require.
35
+ - Ruby code embedded in ERB, Slim etc. templates can interact with this object graph to do funky stuff like:
36
+ - including the rendered contents of another object (ie. partials)
37
+ - query the graph for certain objects (eg. "all objects in `/posts` that have `published_at` set")
38
+ - and much more, I guess!
39
+ - When a `_layout` object is available in the same folder as the rendered object, it will be used to wrap the object's rendered output. These layout files stack, so you can have a `/posts/_layout.erb` with the layout for a single post, and a `/_layout.erb` with the layout of your site.
40
+ - When a `_view.rb` object is available in the same folder as the rendered object, it will be evaluated against the current view, allowing you to define your own view helpers. Like layouts, these will stack.
41
+ - Files and folders starting with underscores (eg. `_header.html`) will never be exported.
22
42
 
23
43
  ## License
24
44
 
data/lib/flutterby.rb CHANGED
@@ -2,6 +2,7 @@ require "flutterby/version"
2
2
  require "flutterby/entity"
3
3
  require "flutterby/file"
4
4
  require "flutterby/folder"
5
+ require "flutterby/filters"
5
6
  require "flutterby/view"
6
7
  require "flutterby/server"
7
8
 
@@ -1,19 +1,18 @@
1
1
  module Flutterby
2
2
  class Entity
3
- attr_accessor :parent
4
- attr_reader :name, :ext, :filters, :fs_path, :data, :children
3
+ attr_accessor :parent, :ext
4
+ attr_reader :name, :filters, :fs_path, :data, :children
5
5
 
6
6
  def initialize(name, parent: nil, fs_path: nil)
7
+ @parent = parent
7
8
  @data = {}
8
9
  reset_children!
9
10
 
10
11
  # Extract name, extension, and filters from given name
11
- parts = name.split(".")
12
- @name = parts.shift
13
- @ext = parts.shift
12
+ parts = name.split(".")
13
+ @name = parts.shift
14
14
  @filters = parts.reverse
15
-
16
- self.parent = parent
15
+ @ext = @filters.last || "html"
17
16
 
18
17
  # If a filesystem path was given, read the entity from disk
19
18
  if fs_path
@@ -61,7 +60,7 @@ module Flutterby
61
60
  end
62
61
 
63
62
  def url
64
- @url ||= ::File.join(parent ? parent.url : "/", full_name)
63
+ ::File.join(parent ? parent.url : "/", full_name)
65
64
  end
66
65
 
67
66
  def full_fs_path(base:)
@@ -144,7 +143,7 @@ module Flutterby
144
143
  end
145
144
 
146
145
  def full_name
147
- @full_name ||= [name, ext].compact.join(".")
146
+ [name, ext].compact.join(".")
148
147
  end
149
148
 
150
149
  def page?
@@ -8,15 +8,15 @@ require 'json'
8
8
 
9
9
  module Flutterby
10
10
  class File < Entity
11
- attr_reader :contents
11
+ attr_accessor :source, :body
12
12
 
13
13
  def reload!
14
- @filtered_contents = nil
14
+ @body = nil
15
15
  super
16
16
  end
17
17
 
18
18
  def read
19
- @contents = ::File.read(fs_path)
19
+ @source = ::File.read(fs_path)
20
20
 
21
21
  # Extract date from name
22
22
  if name =~ %r{^(\d\d\d\d\-\d\d?\-\d\d?)\-}
@@ -36,32 +36,21 @@ module Flutterby
36
36
  data = {}
37
37
 
38
38
  # YAML Front Matter
39
- if @contents.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
39
+ if @source.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
40
40
  data.merge! YAML.load($1)
41
41
  end
42
42
 
43
43
  # TOML Front Matter
44
- if @contents.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
44
+ if @source.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
45
45
  data.merge! TOML.parse($1)
46
46
  end
47
47
 
48
48
  data
49
49
  end
50
50
 
51
- def filtered_contents
52
- @filtered_contents ||= begin
53
- result = @contents
54
-
55
- # Apply all filters
56
- filters.each do |filter|
57
- meth = "process_#{filter}"
58
- if respond_to?(meth)
59
- result = send(meth, result)
60
- end
61
- end
62
-
63
- result
64
- end
51
+ def body
52
+ Filters.apply!(self) if @body.nil?
53
+ @body
65
54
  end
66
55
 
67
56
  def page?
@@ -76,31 +65,12 @@ module Flutterby
76
65
  end
77
66
  end
78
67
 
79
- def process_erb(input)
80
- tilt = Tilt["erb"].new { input }
81
- tilt.render(view)
82
- end
83
-
84
- def process_slim(input)
85
- tilt = Tilt["slim"].new { input }
86
- tilt.render(view)
87
- end
88
-
89
- def process_md(input)
90
- Slodown::Formatter.new(input).complete.to_s
91
- end
92
-
93
- def process_scss(input)
94
- engine = Sass::Engine.new(input, syntax: :scss)
95
- engine.render
96
- end
97
-
98
68
  def read_json
99
- data.merge!(JSON.parse(contents))
69
+ data.merge!(JSON.parse(@source))
100
70
  end
101
71
 
102
72
  def read_yaml
103
- data.merge!(YAML.load(contents))
73
+ data.merge!(YAML.load(@source))
104
74
  end
105
75
 
106
76
  def apply_layout(input)
@@ -117,7 +87,7 @@ module Flutterby
117
87
 
118
88
  # Apply all layouts in order
119
89
  layouts.each do |layout|
120
- tilt = Tilt[layout.ext].new { layout.contents }
90
+ tilt = Tilt[layout.ext].new { layout.source }
121
91
  output = tilt.render(view) { output }
122
92
  end
123
93
 
@@ -129,8 +99,7 @@ module Flutterby
129
99
  end
130
100
 
131
101
  def render(layout: true)
132
- rendered = filtered_contents
133
- (layout && apply_layout?) ? apply_layout(rendered) : rendered
102
+ (layout && apply_layout?) ? apply_layout(body) : body
134
103
  end
135
104
 
136
105
  def write_static(path)
@@ -0,0 +1,41 @@
1
+ module Flutterby
2
+ module Filters
3
+ def apply!(file)
4
+ body = file.source
5
+
6
+ # Apply all filters
7
+ file.filters.each do |filter|
8
+ meth = "process_#{filter}"
9
+
10
+ if Filters.respond_to?(meth)
11
+ body = Filters.send(meth, body, file)
12
+ end
13
+ end
14
+
15
+ file.body = body
16
+ end
17
+
18
+ def process_erb(input, file)
19
+ tilt("erb", input).render(file.view)
20
+ end
21
+
22
+ def process_slim(input, file)
23
+ tilt("slim", input).render(file.view)
24
+ end
25
+
26
+ def process_md(input, file)
27
+ file.ext = "html"
28
+ Slodown::Formatter.new(input).complete.to_s
29
+ end
30
+
31
+ def process_scss(input, file)
32
+ Sass::Engine.new(input, syntax: :scss).render
33
+ end
34
+
35
+ def tilt(format, body)
36
+ Tilt[format].new { body }
37
+ end
38
+
39
+ extend self
40
+ end
41
+ end
@@ -22,7 +22,7 @@ module Flutterby
22
22
  if view_entity = find("_view.rb")
23
23
  case view_entity.ext
24
24
  when "rb" then
25
- view.instance_eval(view_entity.contents)
25
+ view.instance_eval(view_entity.source)
26
26
  else
27
27
  raise "Unknown view extension #{view_entity.full_name}"
28
28
  end
@@ -1,3 +1,3 @@
1
1
  module Flutterby
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
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.0.8
4
+ version: 0.0.9
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-06 00:00:00.000000000 Z
11
+ date: 2017-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -241,24 +241,15 @@ files:
241
241
  - bin/setup
242
242
  - exe/flutterby
243
243
  - flutterby.gemspec
244
- - in/_layout.erb
245
- - in/about.html.md
246
- - in/contact.html.erb
247
- - in/index.html.erb
248
- - in/posts/_layout.slim
249
- - in/posts/hello-world.html.md
250
- - in/posts/really-old-blog-post.html.md
251
- - in/slim-test.html.slim
252
- - in/styles.css.scss
253
244
  - lib/flutterby.rb
254
245
  - lib/flutterby/cli.rb
255
246
  - lib/flutterby/entity.rb
256
247
  - lib/flutterby/file.rb
248
+ - lib/flutterby/filters.rb
257
249
  - lib/flutterby/folder.rb
258
250
  - lib/flutterby/server.rb
259
251
  - lib/flutterby/version.rb
260
252
  - lib/flutterby/view.rb
261
- - out/.gitkeep
262
253
  homepage: https://github.com/hmans/flutterby
263
254
  licenses:
264
255
  - MIT
@@ -279,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
279
270
  version: '0'
280
271
  requirements: []
281
272
  rubyforge_project:
282
- rubygems_version: 2.5.2
273
+ rubygems_version: 2.6.8
283
274
  signing_key:
284
275
  specification_version: 4
285
276
  summary: There are many static site generators. This is mine.
data/in/_layout.erb DELETED
@@ -1,19 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <title>The Blawg of Hendrik Mans</title>
6
- <link rel="stylesheet" href="/styles.css">
7
- </head>
8
- <body>
9
- <div class="container">
10
- <nav role="main">
11
- <a href="/">hmans is blogging, yo</a>
12
- </nav>
13
-
14
- <main role="main">
15
- <%= yield %>
16
- </main>
17
- </div>
18
- </body>
19
- </html>
data/in/about.html.md DELETED
@@ -1,3 +0,0 @@
1
- # I'm Markdown
2
-
3
- And that's cool!
data/in/contact.html.erb DELETED
@@ -1,3 +0,0 @@
1
- <h1>Contact</h1>
2
-
3
- <p>This is really just a test for <%= "ERB" %>. \o/</p>
data/in/index.html.erb DELETED
@@ -1,11 +0,0 @@
1
- <h1>Hendrik Mans</h1>
2
-
3
- <h3>Latest Posts</h3>
4
-
5
- <ul>
6
- <% entity.root.find('posts').pages.sort_by {|p| p.data['date'] }.reverse.each do |post| %>
7
- <li>
8
- <a href="<%= post.url %>"><%= post.data["title"] %></a>
9
- </li>
10
- <% end %>
11
- </ul>
@@ -1,7 +0,0 @@
1
- article.post
2
- .meta
3
- = date_format entity.data["date"], "%B %e, %Y"
4
-
5
- h2 = entity.data["title"]
6
-
7
- == entity.contents
@@ -1,6 +0,0 @@
1
- +++
2
- title = "Hello World"
3
- date = 2017-01-04
4
- +++
5
-
6
- Yay!
@@ -1,8 +0,0 @@
1
- +++
2
- title = "This is a blog post from 2016"
3
- date = 2016-12-08
4
- +++
5
-
6
- I got 40 today.
7
-
8
- Hooray!
@@ -1,3 +0,0 @@
1
- h1 hi!
2
-
3
- p this is a test to see if Slim support works.
data/in/styles.css.scss DELETED
@@ -1,160 +0,0 @@
1
- @import 'https://fonts.googleapis.com/css?family=Noto+Sans:400,700,900|EB+Garamond';
2
-
3
- $col1: steelblue;
4
- $col2: peru;
5
- $col3: rgb(138, 138, 138);
6
- $col-link: #666;
7
-
8
- $font: 16px/1.5 "Noto Sans","Helvetica Neue",Arial,sans-serif;
9
-
10
- * { box-sizing: inherit; }
11
- html, body { box-sizing: border-box; }
12
-
13
- body {
14
- font: $font;
15
- background-color: white;
16
- color: #333;
17
- }
18
-
19
- .container {
20
- margin-left: auto;
21
- margin-right: auto;
22
- max-width: 800px;
23
- padding: 50px;
24
- }
25
-
26
- nav[role="main"] {
27
- color: grey;
28
- font-size: 0.825em;
29
-
30
- a { color: inherit; }
31
- }
32
-
33
- main {
34
- margin-top: 2em;
35
- }
36
-
37
- h1, h2, h3, h4, h5, h6 {
38
- font-size: inherit;
39
- }
40
-
41
- a {
42
- color: $col1;
43
- }
44
-
45
-
46
-
47
- /* action lists */
48
- ul.actions {
49
- list-style: none;
50
- padding-left: 0;
51
- li {
52
- display: inline-block;
53
- margin-right: 0.5em;
54
- }
55
- }
56
-
57
-
58
- /* buttons */
59
- button, a.button {
60
- display: inline-block;
61
- line-height: 2em;
62
- padding: 0 1em;
63
- border-radius: 2px;
64
- background-color: $col1;
65
- color: white;
66
- text-decoration: none;
67
- font-size: 0.825em;
68
- border: none;
69
- cursor: pointer;
70
-
71
- &.button-grey {
72
- background-color: lightgrey;
73
- color: dimgrey;
74
- }
75
-
76
- &.button-red {
77
- background-color: tomato;
78
- }
79
- }
80
-
81
-
82
-
83
-
84
-
85
- /* forms */
86
- label {
87
- display: block;
88
- font-weight: bold;
89
- abbr { color: grey; text-decoration: none !important }
90
- }
91
-
92
- input, textarea, select {
93
- font: inherit;
94
- }
95
-
96
- input.string, input.password, input.email, textarea {
97
- width: 100%;
98
- padding: 5px;
99
- border: 1px solid lightgrey;
100
- }
101
-
102
- input[type="submit"] {
103
- @extend button;
104
- }
105
-
106
- .input.field_with_errors {
107
- input, textarea { border-color: crimson }
108
- }
109
-
110
- textarea {
111
- height: 7em;
112
- }
113
-
114
- textarea#post_body {
115
- height: 18em;
116
- }
117
-
118
- .input {
119
- margin: 1em 0;
120
- }
121
-
122
- .error, .help-block {
123
- color: crimson;
124
- font-size: 0.825em;
125
- }
126
-
127
-
128
- /* stupid non-UJS link forms */
129
-
130
- form.link {
131
- display: inline;
132
- }
133
-
134
- /* post specific */
135
-
136
- article.post {
137
- margin: 4em 0;
138
-
139
- .meta {
140
- color: lightgrey;
141
- font-size: 0.825em;
142
-
143
- a {
144
- color: inherit;
145
- text-decoration: none;
146
- &:hover {
147
- text-decoration: underline;
148
- }
149
- }
150
- }
151
-
152
- h1 {
153
- font: 44px "EB Garamond", serif;
154
- color: #555;
155
- }
156
-
157
- h2 {
158
- color: $col2;
159
- }
160
- }