flora 0.12.0 → 1.0.1
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 +4 -4
- data/.document +2 -0
- data/.woodpecker.yml +16 -0
- data/lib/flora/config.rb +13 -9
- data/lib/flora/factory.rb +2 -2
- data/lib/flora/lilac.rb +9 -0
- data/lib/flora/plugin_manager.rb +28 -0
- data/lib/flora/plugins/blog.rb +20 -9
- data/lib/flora/plugins/redirector.rb +1 -1
- data/lib/flora/plugins/static_files.rb +12 -1
- data/lib/flora/project/blueprint/has_layout.rb +54 -0
- data/lib/flora/project/blueprint/markdown.rb +1 -1
- data/lib/flora/project/blueprint/ruby_html.rb +2 -2
- data/lib/flora/project/blueprint.rb +5 -11
- data/lib/flora/project.rb +5 -1
- data/lib/flora/version.rb +1 -1
- data/lib/flora.rb +9 -21
- metadata +6 -3
- data/lib/flora/project/blueprint/nestable.rb +0 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffea457870b0ae28e03a55fe032421257ea9eceb19ff282727c01b888a24c05b
|
|
4
|
+
data.tar.gz: 91d44f3cefd76ee01cbc834163d075564bf5ea9df5adb1487d143e089868d07a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2fb5f500e39eb1f4f143445bc460a0a501a1bfca8459c8eb0d50ddaee3d66882c731fb823ffc4b3dc2717b5186df6be9d42810cb0d0293497434f06d171c9ec
|
|
7
|
+
data.tar.gz: bf5d0b9c5d00e2bff223d3aec48b1225e397adea87eac7a780903a1d337e275efefe09a15323508f28c83b19adc6a303b4a6d504adac62663b5067e1b7f5b43c
|
data/.document
ADDED
data/.woodpecker.yml
ADDED
data/lib/flora/config.rb
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
# This is the user-visible configuration class. It lives in ROOT/_config.rb.
|
|
2
2
|
class Flora::Config
|
|
3
3
|
|
|
4
|
-
def initialize(file,
|
|
4
|
+
def initialize(file, plugin_manager)
|
|
5
5
|
@file = file
|
|
6
|
-
@
|
|
7
|
-
load if @file.exist?
|
|
6
|
+
@plugin_manager = plugin_manager
|
|
8
7
|
end
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def use(mod)
|
|
12
|
-
@
|
|
11
|
+
@plugin_manager.load(mod)
|
|
12
|
+
|
|
13
|
+
# TODO: ideally, this would live in PluginManager, but it needs to pass
|
|
14
|
+
# Config.
|
|
15
|
+
mod.loaded(self) if mod.respond_to?(:loaded)
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
def extend_view(mod)
|
|
17
|
-
|
|
20
|
+
@plugin_manager.global_load(mod)
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
# :nodoc:
|
|
25
|
+
def load
|
|
26
|
+
return unless @file.exist?
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
28
|
+
instance_eval(@file.read)
|
|
29
|
+
end
|
|
26
30
|
|
|
27
31
|
end
|
data/lib/flora/factory.rb
CHANGED
|
@@ -14,10 +14,10 @@ class Flora::Factory
|
|
|
14
14
|
|
|
15
15
|
@project.blueprints.each do |blueprint|
|
|
16
16
|
out_filename = out_dir.join(blueprint.page_name)
|
|
17
|
+
@logger.debug("[Flora] #{blueprint.file} => #{out_filename}")
|
|
18
|
+
|
|
17
19
|
FileUtils.mkdir_p(out_filename.dirname) unless out_filename.dirname.exist?
|
|
18
20
|
out_filename.write(blueprint.render)
|
|
19
|
-
|
|
20
|
-
@logger.debug("[Flora] #{blueprint.file} => #{out_filename}")
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
data/lib/flora/lilac.rb
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Flora::PluginManager
|
|
2
|
+
|
|
3
|
+
def initialize(logger)
|
|
4
|
+
@logger = logger
|
|
5
|
+
@pluggables = {}
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_pluggable_class(klass)
|
|
10
|
+
@pluggables[klass] = Class.new(klass)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load(mod)
|
|
15
|
+
@pluggables.each do |base_class, anon_class|
|
|
16
|
+
name = "#{base_class.name.split('::').last}Methods"
|
|
17
|
+
anon_class.include(mod.const_get(name)) if mod.const_defined?(name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
@logger.debug("[Flora] Plugin #{mod} loaded")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def global_load(mod)
|
|
25
|
+
Kernel.include(mod)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
data/lib/flora/plugins/blog.rb
CHANGED
|
@@ -68,7 +68,6 @@ module Flora::Plugins::Blog
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
|
|
72
71
|
# Nokogiri's builder uses method_missing, and some of Lilac's tags are
|
|
73
72
|
# named the same as some of the Atom tags we want to use which causes
|
|
74
73
|
# conflicts. Use this method to get around that!
|
|
@@ -81,17 +80,15 @@ module Flora::Plugins::Blog
|
|
|
81
80
|
|
|
82
81
|
module ProjectMethods
|
|
83
82
|
|
|
84
|
-
def
|
|
85
|
-
|
|
83
|
+
def self.included(base)
|
|
84
|
+
base.class_eval do
|
|
85
|
+
blueprint_classes.prepend(Flora::Plugins::Blog::BlogPost)
|
|
86
|
+
end
|
|
86
87
|
end
|
|
87
88
|
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
module BlueprintMethods
|
|
92
89
|
|
|
93
90
|
def posts
|
|
94
|
-
@
|
|
91
|
+
@dir.glob('posts/**.md').map { Post.new(it, @dir) }.sort_by(&:date).reverse
|
|
95
92
|
end
|
|
96
93
|
|
|
97
94
|
end
|
|
@@ -109,7 +106,7 @@ module Flora::Plugins::Blog
|
|
|
109
106
|
end
|
|
110
107
|
|
|
111
108
|
|
|
112
|
-
module
|
|
109
|
+
module ConfigMethods
|
|
113
110
|
|
|
114
111
|
def self.included(base)
|
|
115
112
|
base.class_eval do
|
|
@@ -119,4 +116,18 @@ module Flora::Plugins::Blog
|
|
|
119
116
|
|
|
120
117
|
end
|
|
121
118
|
|
|
119
|
+
|
|
120
|
+
module ViewExtensions
|
|
121
|
+
|
|
122
|
+
def posts
|
|
123
|
+
@project.posts
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def self.loaded(config)
|
|
130
|
+
config.extend_view(ViewExtensions)
|
|
131
|
+
end
|
|
132
|
+
|
|
122
133
|
end
|
|
@@ -19,7 +19,18 @@ module Flora::Plugins::StaticFiles
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
module
|
|
22
|
+
module ProjectMethods
|
|
23
|
+
|
|
24
|
+
def self.included(base)
|
|
25
|
+
base.class_eval do
|
|
26
|
+
blueprint_classes.prepend(Flora::Plugins::StaticFiles::StaticFile)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
module ConfigMethods
|
|
23
34
|
|
|
24
35
|
def self.included(base)
|
|
25
36
|
base.class_eval do
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# A Blueprint that includes HasLayout is something that can be nested into a
|
|
2
|
+
# Lilac-based layout.
|
|
3
|
+
module Flora::Project::Blueprint::HasLayout
|
|
4
|
+
|
|
5
|
+
def render
|
|
6
|
+
# The Html DSL uses a global variable internally that needs to be reset every time.
|
|
7
|
+
$flora_added = []
|
|
8
|
+
|
|
9
|
+
layouts = find_layouts
|
|
10
|
+
tree = render_internal(layouts, layouts.size) do
|
|
11
|
+
render_lilac
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Flora::Lilac.to_html(tree)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def find_layouts
|
|
21
|
+
layouts = []
|
|
22
|
+
current = @file.parent
|
|
23
|
+
|
|
24
|
+
loop do
|
|
25
|
+
maybe_layout = current.join('./_layout.rb')
|
|
26
|
+
layouts << maybe_layout if maybe_layout.exist?
|
|
27
|
+
|
|
28
|
+
break if current == @project.dir
|
|
29
|
+
current = current.parent
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
layouts
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def render_internal(layouts, i, &block)
|
|
37
|
+
if i <= 0
|
|
38
|
+
return block.call
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
cont = -> { render_internal(layouts, i-1, &block) }
|
|
42
|
+
filename = layouts[i-1].to_s
|
|
43
|
+
eval_with_block(layouts[i-1].read, filename, &cont)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# This exists because the eval'd code will call yield, and yield will always
|
|
48
|
+
# grab the current block passed into the current function. We need that to be
|
|
49
|
+
# a specific proc, not the one passed into render_internal!
|
|
50
|
+
def eval_with_block(str, filename, &block)
|
|
51
|
+
eval(str, binding, filename)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class Flora::Project::Blueprint::RubyHtml < Flora::Project::Blueprint
|
|
2
2
|
|
|
3
|
-
include Flora::Project::Blueprint::
|
|
3
|
+
include Flora::Project::Blueprint::HasLayout
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def self.recognize(file, config)
|
|
@@ -11,7 +11,7 @@ class Flora::Project::Blueprint::RubyHtml < Flora::Project::Blueprint
|
|
|
11
11
|
private
|
|
12
12
|
|
|
13
13
|
def render_lilac
|
|
14
|
-
instance_eval(@file.read)
|
|
14
|
+
instance_eval(@file.read, @file.to_s)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
end
|
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
# A Blueprint is something can be rendered into a
|
|
2
|
-
# looks very different than the
|
|
1
|
+
# A Blueprint is something can be rendered into a page. Sometimes a Blueprint
|
|
2
|
+
# looks very different than the page it renders into, but other times (like for
|
|
3
3
|
# static files), nothing changes.
|
|
4
4
|
class Flora::Project::Blueprint
|
|
5
5
|
|
|
6
6
|
attr_reader(:file)
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
# :nodoc:
|
|
10
|
-
def self.types
|
|
11
|
-
ObjectSpace.each_object(Class).select { it < self }
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
|
|
15
9
|
# Returns true if this Blueprint is appropriate for the file.
|
|
16
10
|
#
|
|
17
11
|
# TODO: should this be an instance method somewhere instead?
|
|
@@ -28,15 +22,15 @@ class Flora::Project::Blueprint
|
|
|
28
22
|
end
|
|
29
23
|
|
|
30
24
|
|
|
31
|
-
# The name of the
|
|
25
|
+
# The name of the page this Blueprint makes. By default this is just the
|
|
32
26
|
# filename, but .html, but subclasses can override this.
|
|
33
27
|
def page_name
|
|
34
28
|
@file.relative_path_from(@project.dir).sub_ext('.html').to_s
|
|
35
29
|
end
|
|
36
30
|
|
|
37
31
|
|
|
38
|
-
# Render a Blueprint into a
|
|
39
|
-
# of whatever the
|
|
32
|
+
# Render a Blueprint into a page for a Website. This is the String contents
|
|
33
|
+
# of whatever the page in the final Website looks like.
|
|
40
34
|
def render
|
|
41
35
|
# Override in subclasses!
|
|
42
36
|
end
|
data/lib/flora/project.rb
CHANGED
|
@@ -9,6 +9,10 @@ class Flora::Project
|
|
|
9
9
|
|
|
10
10
|
IGNORES = ['.git/*', 'lib/**', '**_*.rb']
|
|
11
11
|
|
|
12
|
+
def self.blueprint_classes
|
|
13
|
+
@blueprint_classes ||= [Blueprint::Markdown, Blueprint::RubyHtml]
|
|
14
|
+
end
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def initialize(dir, loader, config)
|
|
14
18
|
@dir = dir
|
|
@@ -38,7 +42,7 @@ class Flora::Project
|
|
|
38
42
|
next if IGNORES.any? { file.fnmatch((@dir / it).to_s) }
|
|
39
43
|
next if file.directory?
|
|
40
44
|
|
|
41
|
-
klass =
|
|
45
|
+
klass = self.class.blueprint_classes.find {
|
|
42
46
|
it.recognize(file.relative_path_from(@dir), @config)
|
|
43
47
|
}
|
|
44
48
|
|
data/lib/flora/version.rb
CHANGED
data/lib/flora.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'fileutils'
|
|
|
5
5
|
require 'logger'
|
|
6
6
|
|
|
7
7
|
loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
|
8
|
+
loader.do_not_eager_load("#{__dir__}/flora/plugins")
|
|
8
9
|
loader.setup
|
|
9
10
|
|
|
10
11
|
class Flora
|
|
@@ -16,19 +17,20 @@ class Flora
|
|
|
16
17
|
dir = Pathname.new(dir)
|
|
17
18
|
|
|
18
19
|
@logger = Logger.new(STDOUT, level: ENV['FLORA_LOG'] || 'info')
|
|
20
|
+
@plugin_manager = PluginManager.new(@logger)
|
|
19
21
|
|
|
20
22
|
# Inject Lilac into the Kernel so it's available everywhere. Just
|
|
21
23
|
# instance_eval isn't enough because it'll be missing in lib/ code.
|
|
22
24
|
#
|
|
23
25
|
# TODO: is there a less disruptive way to do this?
|
|
24
|
-
|
|
26
|
+
@plugin_manager.global_load(Flora::Lilac)
|
|
25
27
|
|
|
26
28
|
# The classes that are pluggable get their own instances to avoid conflicting
|
|
27
29
|
# with other instances of Flora in the same process. This is mostly for the
|
|
28
30
|
# unit tests. Maybe one day we can use Ruby::Box or something here instead.
|
|
29
|
-
@config_class =
|
|
30
|
-
@project_class =
|
|
31
|
-
@factory_class =
|
|
31
|
+
@config_class = @plugin_manager.create_pluggable_class(Config)
|
|
32
|
+
@project_class = @plugin_manager.create_pluggable_class(Project)
|
|
33
|
+
@factory_class = @plugin_manager.create_pluggable_class(Factory)
|
|
32
34
|
|
|
33
35
|
# This has to be loaded before Config so Config can reference lib/ code.
|
|
34
36
|
@project_loader = Zeitwerk::Loader.new
|
|
@@ -38,7 +40,9 @@ class Flora
|
|
|
38
40
|
@project_loader.enable_reloading
|
|
39
41
|
@project_loader.setup
|
|
40
42
|
|
|
41
|
-
@config = @config_class.new(dir.join('_config.rb'),
|
|
43
|
+
@config = @config_class.new(dir.join('_config.rb'), @plugin_manager)
|
|
44
|
+
@config.load
|
|
45
|
+
|
|
42
46
|
@project = @project_class.new(dir, @project_loader, @config)
|
|
43
47
|
@factory = @factory_class.new(@project, @config, @logger)
|
|
44
48
|
end
|
|
@@ -60,17 +64,6 @@ class Flora
|
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
|
|
63
|
-
# TODO: it would be nice if this wasn't exposed here. It's just for Config#plugin.
|
|
64
|
-
def load_plugin(mod)
|
|
65
|
-
@config_class.include(mod::Config) if defined?(mod::Config)
|
|
66
|
-
@project_class.include(mod::ProjectMethods) if defined?(mod::ProjectMethods)
|
|
67
|
-
@factory_class.include(mod::FactoryMethods) if defined?(mod::FactoryMethods)
|
|
68
|
-
|
|
69
|
-
# TODO: make this a little more resilient (like the other classes).
|
|
70
|
-
Flora::Project::Blueprint.include(mod::BlueprintMethods) if defined?(mod::BlueprintMethods)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
|
|
74
67
|
private
|
|
75
68
|
|
|
76
69
|
def bench
|
|
@@ -80,8 +73,3 @@ class Flora
|
|
|
80
73
|
end
|
|
81
74
|
|
|
82
75
|
end
|
|
83
|
-
|
|
84
|
-
# Built-in Blueprints need to be explicitly loaded or else they won't show up
|
|
85
|
-
# in Blueprint.types.
|
|
86
|
-
loader.load_file("#{__dir__}/flora/project/blueprint/ruby_html.rb")
|
|
87
|
-
loader.load_file("#{__dir__}/flora/project/blueprint/markdown.rb")
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flora
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nick Vladimiroff
|
|
@@ -142,6 +142,8 @@ executables:
|
|
|
142
142
|
extensions: []
|
|
143
143
|
extra_rdoc_files: []
|
|
144
144
|
files:
|
|
145
|
+
- ".document"
|
|
146
|
+
- ".woodpecker.yml"
|
|
145
147
|
- LICENSE.txt
|
|
146
148
|
- README.md
|
|
147
149
|
- Rakefile
|
|
@@ -152,14 +154,15 @@ files:
|
|
|
152
154
|
- lib/flora/config.rb
|
|
153
155
|
- lib/flora/factory.rb
|
|
154
156
|
- lib/flora/lilac.rb
|
|
157
|
+
- lib/flora/plugin_manager.rb
|
|
155
158
|
- lib/flora/plugins/blog.rb
|
|
156
159
|
- lib/flora/plugins/blog/post.rb
|
|
157
160
|
- lib/flora/plugins/redirector.rb
|
|
158
161
|
- lib/flora/plugins/static_files.rb
|
|
159
162
|
- lib/flora/project.rb
|
|
160
163
|
- lib/flora/project/blueprint.rb
|
|
164
|
+
- lib/flora/project/blueprint/has_layout.rb
|
|
161
165
|
- lib/flora/project/blueprint/markdown.rb
|
|
162
|
-
- lib/flora/project/blueprint/nestable.rb
|
|
163
166
|
- lib/flora/project/blueprint/ruby_html.rb
|
|
164
167
|
- lib/flora/version.rb
|
|
165
168
|
- tmp/.keep
|
|
@@ -176,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
176
179
|
requirements:
|
|
177
180
|
- - ">="
|
|
178
181
|
- !ruby/object:Gem::Version
|
|
179
|
-
version: 3.
|
|
182
|
+
version: 3.4.0
|
|
180
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
184
|
requirements:
|
|
182
185
|
- - ">="
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# A Blueprint that includes Nestable is something that can be nested into a
|
|
2
|
-
# Lilac-based layout.
|
|
3
|
-
module Flora::Project::Blueprint::Nestable
|
|
4
|
-
|
|
5
|
-
def render
|
|
6
|
-
# The Html DSL uses a global variable internally that needs to be reset every time.
|
|
7
|
-
$flora_added = []
|
|
8
|
-
|
|
9
|
-
layouts = find_layouts
|
|
10
|
-
tree = render_internal(layouts, layouts.size) do
|
|
11
|
-
render_lilac
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
Flora::Lilac.to_html(tree)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def find_layouts
|
|
21
|
-
layouts = []
|
|
22
|
-
|
|
23
|
-
@file.ascend do |dir|
|
|
24
|
-
maybe_layout = dir.join('_layout.rb')
|
|
25
|
-
layouts << maybe_layout if maybe_layout.exist?
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Ascend doesn't go to the top level directory.
|
|
29
|
-
# TODO: Make this code less brittle.
|
|
30
|
-
maybe_layout = Pathname.new('./_layout.rb')
|
|
31
|
-
layouts << maybe_layout if maybe_layout.exist?
|
|
32
|
-
|
|
33
|
-
layouts
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def render_internal(layouts, i, &block)
|
|
38
|
-
if i <= 0
|
|
39
|
-
return block.call
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
cont = -> { render_internal(layouts, i-1, &block) }
|
|
43
|
-
eval_with_block(layouts[i-1].read, &cont)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def eval_with_block(str, &block)
|
|
48
|
-
eval(str)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
end
|