yarrow 0.5.1 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -4
- data/README.md +13 -19
- data/Rakefile +15 -1
- data/lib/yarrow.rb +7 -6
- data/lib/yarrow/config.rb +59 -0
- data/lib/yarrow/configuration.rb +37 -63
- data/lib/yarrow/content/collection_expander.rb +3 -4
- data/lib/yarrow/content/content_type.rb +10 -6
- data/lib/yarrow/content/graph.rb +2 -27
- data/lib/yarrow/extensions.rb +1 -0
- data/lib/yarrow/extensions/mementus.rb +24 -0
- data/lib/yarrow/output/context.rb +0 -4
- data/lib/yarrow/output/generator.rb +2 -2
- data/lib/yarrow/output/web/indexed_file.rb +39 -0
- data/lib/yarrow/schema.rb +132 -0
- data/lib/yarrow/schema/validations/array.rb +0 -0
- data/lib/yarrow/schema/validations/object.rb +0 -0
- data/lib/yarrow/schema/validations/string.rb +0 -0
- data/lib/yarrow/server.rb +7 -5
- data/lib/yarrow/symbols.rb +19 -0
- data/lib/yarrow/tools/content_utils.rb +74 -0
- data/lib/yarrow/tools/front_matter.rb +4 -2
- data/lib/yarrow/version.rb +3 -2
- data/lib/yarrow/web/html_document.rb +9 -0
- data/lib/yarrow/web/manifest.rb +9 -0
- data/lib/yarrow/web/static_asset.rb +9 -0
- data/lib/yarrow/web/template.rb +9 -0
- data/yarrow.gemspec +2 -3
- metadata +33 -37
- data/lib/yarrow/html.rb +0 -1
- data/lib/yarrow/html/asset_tags.rb +0 -59
- data/lib/yarrow/html/content_tags.rb +0 -7
- data/lib/yarrow/tools/output_file.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b44d99f6d8696237f4e571ab6f6301fe337c93c6ff218e735acd1c0ed3fbe29
|
4
|
+
data.tar.gz: 12419fb4e83374e8ff79700fa8a6b14cfcf3ed5a44cd94adc91f8885a3e7f9fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af1fdac9c1ac87957f098dd5fe1e3e22d7ac9b78756838226a596a8262bcd438c185cad81dfa3b5ae5f3f071d9c203afdea5e668a79d9b80096a140e310aef3b
|
7
|
+
data.tar.gz: e237d7964723ad433fab071ef36026979f5a5d2010fc11ce3b787566b8f4c12232b47c8b5dadb0043e93db1d5cd8679b99ec71db303269d244c1e8687b0204aa
|
data/.github/workflows/ruby.yml
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
name:
|
1
|
+
name: ruby
|
2
2
|
on:
|
3
3
|
push:
|
4
|
-
branches: [
|
4
|
+
branches: [ main ]
|
5
5
|
pull_request:
|
6
|
-
branches: [
|
6
|
+
branches: [ main ]
|
7
7
|
jobs:
|
8
8
|
test:
|
9
9
|
strategy:
|
10
10
|
fail-fast: false
|
11
11
|
matrix:
|
12
12
|
os: [ubuntu-latest, macos-latest]
|
13
|
-
ruby: [2.7, '3.0', jruby]
|
13
|
+
ruby: [2.7, '3.0', jruby-head]
|
14
14
|
runs-on: ${{ matrix.os }}
|
15
15
|
steps:
|
16
16
|
- uses: actions/checkout@v2
|
data/README.md
CHANGED
@@ -1,21 +1,15 @@
|
|
1
1
|
Yarrow
|
2
2
|
======
|
3
3
|
|
4
|
-
[![Gem Version](
|
5
|
-
[![Build Status](
|
6
|
-
[![Dependency Status](http://img.shields.io/gemnasium/maetl/yarrow.svg)][gemnasium]
|
7
|
-
[![Code Climate](http://img.shields.io/codeclimate/github/maetl/yarrow.svg)][codeclimate]
|
8
|
-
[![Coverage Status](http://img.shields.io/coveralls/maetl/yarrow.svg)][coveralls]
|
4
|
+
[![Gem Version](https://img.shields.io/gem/v/yarrow.svg)][gem]
|
5
|
+
[![Build Status](https://img.shields.io/github/workflow/status/maetl/yarrow/ruby/main)][github]
|
9
6
|
|
10
7
|
[gem]: https://rubygems.org/gems/yarrow
|
11
|
-
[
|
12
|
-
[gemnasium]: https://gemnasium.com/maetl/yarrow
|
13
|
-
[codeclimate]: https://codeclimate.com/github/maetl/yarrow
|
14
|
-
[coveralls]: https://coveralls.io/r/maetl/yarrow
|
8
|
+
[github]: https://github.com/maetl/yarrow
|
15
9
|
|
16
|
-
Yarrow is a
|
10
|
+
Yarrow is a framework for generating well structured publishing outputs from a variety of input sources.
|
17
11
|
|
18
|
-
Unlike most static site generators and code documentation tools, Yarrow is written with design and content-strategy in mind. It does not impose its own structure on your content. This makes it
|
12
|
+
Unlike most static site generators and code documentation tools, Yarrow is written with design and content-strategy in mind. It does not impose its own structure on your content. This makes it useful for building style guides, technical docs and complex ebooks as well as static sites and blogs.
|
19
13
|
|
20
14
|
Installation
|
21
15
|
------------
|
@@ -37,7 +31,7 @@ Status
|
|
37
31
|
|
38
32
|
Yarrow is an extraction from several existing private documentation projects. This repo is in alpha state, which means that many of the useful features are not yet folded into this codebase.
|
39
33
|
|
40
|
-
Yarrow is being slowly developed as a part-time project to scratch a few itches. New features and bugfixes are pushed straight to
|
34
|
+
Yarrow is being slowly developed as a part-time project to scratch a few itches. New features and bugfixes are pushed straight to `main`, and releases of the Gem are kept more or less in sync with the planned roadmap.
|
41
35
|
|
42
36
|
Roadmap
|
43
37
|
-------
|
@@ -46,13 +40,13 @@ A rough sketch of the project direction.
|
|
46
40
|
|
47
41
|
| Version | Features |
|
48
42
|
|---------|----------|
|
49
|
-
| `0.
|
50
|
-
| `0.
|
51
|
-
| `0.
|
52
|
-
| `0.
|
53
|
-
| `0.
|
54
|
-
| `0.
|
55
|
-
| `0
|
43
|
+
| `0.6` | Default media type mapping, graph collectors, markup converters |
|
44
|
+
| `0.7` | Content model/object mapping, template/site context |
|
45
|
+
| `0.8` | HTML publishing workflow |
|
46
|
+
| `0.9` | PDF publishing workflow |
|
47
|
+
| `0.10` | Media and video publishing workflow |
|
48
|
+
| `0.11` | Generic command line runner |
|
49
|
+
| `1.0` | Refactoring, performance fixes, lock down API |
|
56
50
|
|
57
51
|
License
|
58
52
|
-------
|
data/Rakefile
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("./lib", __dir__)
|
2
|
+
require "yarrow"
|
3
|
+
|
4
|
+
task :version do
|
5
|
+
puts Yarrow::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
task :build do
|
9
|
+
sh "gem build yarrow.gemspec"
|
10
|
+
end
|
11
|
+
|
12
|
+
task :publish do
|
13
|
+
sh "gem push yarrow-#{Yarrow::VERSION}.gem"
|
14
|
+
end
|
1
15
|
|
2
16
|
task :clean do
|
3
|
-
sh
|
17
|
+
sh "rm yarrow-*.gem"
|
4
18
|
end
|
data/lib/yarrow.rb
CHANGED
@@ -1,28 +1,29 @@
|
|
1
|
-
require '
|
1
|
+
require 'pathname'
|
2
2
|
require 'yaml'
|
3
|
-
require 'active_support/inflector'
|
4
3
|
|
5
4
|
require 'yarrow/version'
|
5
|
+
require 'yarrow/extensions'
|
6
|
+
require 'yarrow/symbols'
|
6
7
|
require 'yarrow/logging'
|
8
|
+
require 'yarrow/schema'
|
9
|
+
require 'yarrow/config'
|
7
10
|
require 'yarrow/configuration'
|
8
11
|
require 'yarrow/console_runner'
|
9
12
|
require 'yarrow/generator'
|
10
|
-
require 'yarrow/assets'
|
11
13
|
require 'yarrow/tools/front_matter'
|
14
|
+
require 'yarrow/tools/content_utils'
|
12
15
|
require 'yarrow/content/graph'
|
13
16
|
require 'yarrow/content/content_type'
|
14
17
|
require 'yarrow/content/source'
|
15
18
|
require 'yarrow/content/source_collector'
|
16
19
|
require 'yarrow/content/collection_expander'
|
17
|
-
require 'yarrow/html/asset_tags'
|
18
20
|
require 'yarrow/output/mapper'
|
19
21
|
require 'yarrow/output/generator'
|
20
22
|
require 'yarrow/output/context'
|
23
|
+
require 'yarrow/output/web/indexed_file'
|
21
24
|
require 'yarrow/content_map'
|
22
|
-
require 'yarrow/html'
|
23
25
|
require 'yarrow/server'
|
24
26
|
require 'yarrow/server/livereload'
|
25
|
-
require 'yarrow/schema'
|
26
27
|
|
27
28
|
require 'yarrow/process/workflow'
|
28
29
|
require 'yarrow/process/step_processor'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Replacement for the legacy Hashie::Mash/Module mixin configuration
|
2
|
+
# pattern. This provides the same API (chaining nested attribute calls) but
|
3
|
+
# handles schema validation and doesn’t pollute other namespaces.
|
4
|
+
module Yarrow
|
5
|
+
module Config
|
6
|
+
# Basic defaults which can be used to populate HTML metadata as well as
|
7
|
+
# used in CLI listings and other generated docs. The default H1 if no
|
8
|
+
# specific output config or template themes are provided.
|
9
|
+
#
|
10
|
+
# For larger web publishing projects, this should be moved out into a
|
11
|
+
# template context or language/translation files to make it editable
|
12
|
+
# for a larger group of people.
|
13
|
+
Meta = Yarrow::Schema::Value.new(
|
14
|
+
:title,
|
15
|
+
:author
|
16
|
+
# :copyright TODO: what other basic details to include?
|
17
|
+
)
|
18
|
+
|
19
|
+
# Dev server config. This is mainly useful if you want to set up a specific
|
20
|
+
# chain of Rack middleware and handlers. If you don’t care about default
|
21
|
+
# directory indexes or port handling, you can completely ignore this.
|
22
|
+
#
|
23
|
+
# There are many better live reloading options available in JS, so the Rack
|
24
|
+
# infrastructure here should be ignored for UI-heavy jobs. It’s otherwise
|
25
|
+
# fine for slower-paced general purpose web publishing.
|
26
|
+
#
|
27
|
+
# The default index config could possibly move into a dedicated namespace
|
28
|
+
# in future if it makes sense to use the underlying graph infrastructure
|
29
|
+
# as a live lookup rather than a compiler-generated artifact. This would
|
30
|
+
# mean rather than doing a ls on the directory, the index pages would
|
31
|
+
# grab a list of entries out of a graph projection for the directory.
|
32
|
+
Server = Yarrow::Schema::Value.new(
|
33
|
+
:live_reload,
|
34
|
+
:auto_index,
|
35
|
+
:default_index,
|
36
|
+
:default_type,
|
37
|
+
:port,
|
38
|
+
:host,
|
39
|
+
:handler,
|
40
|
+
:middleware,
|
41
|
+
:root_dir
|
42
|
+
)
|
43
|
+
|
44
|
+
# Top level root config namespace. Source, content and output are directory
|
45
|
+
# paths and should be the only required defaults for a complete batch run.
|
46
|
+
#
|
47
|
+
# Additional server config is optional and only needed if running the dev
|
48
|
+
# server locally.
|
49
|
+
#
|
50
|
+
# TODO: meta should be union of Type::Optional and Config::Meta
|
51
|
+
Instance = Yarrow::Schema::Value.new(
|
52
|
+
source: Pathname,
|
53
|
+
content: Pathname,
|
54
|
+
output_dir: Pathname,
|
55
|
+
meta: Yarrow::Schema::Type::Any,
|
56
|
+
server: Yarrow::Schema::Type::Any
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
data/lib/yarrow/configuration.rb
CHANGED
@@ -1,50 +1,6 @@
|
|
1
1
|
module Yarrow
|
2
|
-
|
3
|
-
# Hash-like object containing runtime configuration values. Can be accessed indifferently
|
4
|
-
# via object style lookups or symbol keys.
|
5
|
-
#
|
6
|
-
class Configuration < Hashie::Mash
|
2
|
+
class Configuration
|
7
3
|
class << self
|
8
|
-
##
|
9
|
-
# Provides access to the registered global configuration.
|
10
|
-
#
|
11
|
-
# If no configuration is registered, returns a blank object.
|
12
|
-
#
|
13
|
-
# @return [Yarrow::Configuration]
|
14
|
-
#
|
15
|
-
def instance
|
16
|
-
@@configuration ||= self.new
|
17
|
-
end
|
18
|
-
|
19
|
-
##
|
20
|
-
# Loads and registers a global configuration instance.
|
21
|
-
#
|
22
|
-
# This will reset any previously initialized configuration.
|
23
|
-
#
|
24
|
-
# @param [String] path to YAML file
|
25
|
-
#
|
26
|
-
def register(file)
|
27
|
-
@@configuration = load(file)
|
28
|
-
end
|
29
|
-
|
30
|
-
##
|
31
|
-
# Loads and registers a global configuration instance with
|
32
|
-
# library-provided defaults.
|
33
|
-
#
|
34
|
-
# This will reset any previously initialized configuration.
|
35
|
-
#
|
36
|
-
def register_defaults
|
37
|
-
@@configuration = load_defaults
|
38
|
-
end
|
39
|
-
|
40
|
-
##
|
41
|
-
# Clears the global configuration to the empty default.
|
42
|
-
#
|
43
|
-
def clear
|
44
|
-
@@configuration = self.new
|
45
|
-
end
|
46
|
-
|
47
|
-
##
|
48
4
|
# Merges the given configuration or hash-like object with the
|
49
5
|
# registered global configuration.
|
50
6
|
#
|
@@ -54,18 +10,16 @@ module Yarrow
|
|
54
10
|
instance.deep_merge!(config)
|
55
11
|
end
|
56
12
|
|
57
|
-
##
|
58
13
|
# Loads a configuration object from the given YAML file.
|
59
14
|
#
|
60
15
|
# @param [String] path to YAML file
|
61
16
|
#
|
62
|
-
# @return [Yarrow::
|
17
|
+
# @return [Yarrow::Config]
|
63
18
|
#
|
64
19
|
def load(file)
|
65
|
-
|
20
|
+
coerce_config_struct(YAML.load(File.read(file), symbolize_names: true))
|
66
21
|
end
|
67
22
|
|
68
|
-
##
|
69
23
|
# Yarrow is distributed with a `defaults.yml` which provides minimum
|
70
24
|
# boostrap configuration and default settings for various internal
|
71
25
|
# classes. Use this method to automatically load these defaults.
|
@@ -74,21 +28,41 @@ module Yarrow
|
|
74
28
|
def load_defaults
|
75
29
|
load(File.join(File.dirname(__FILE__), 'defaults.yml'))
|
76
30
|
end
|
77
|
-
end
|
78
|
-
end
|
79
31
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
32
|
+
private
|
33
|
+
|
34
|
+
# TODO: this should be folded into the schema machinery with type coercions
|
35
|
+
def coerce_config_struct(config)
|
36
|
+
meta_obj = if config.key?(:meta)
|
37
|
+
Yarrow::Config::Meta.new(
|
38
|
+
title: config[:meta][:title],
|
39
|
+
author: config[:meta][:author]
|
40
|
+
)
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
server_obj = if config.key?(:server)
|
46
|
+
Yarrow::Config::Server.new(**config[:server])
|
47
|
+
else
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: messy hack to get rid of Hashie::Mash, this should either be
|
52
|
+
# automated as part of the schema types or a default value should be
|
53
|
+
# generated here (eg: `"#{Dir.pwd}/docs"`)
|
54
|
+
out_dir_or_string = config[:output_dir] || ""
|
55
|
+
source_dir_or_string = config[:source] || ""
|
56
|
+
content_dir_or_string = config[:content] || ""
|
57
|
+
|
58
|
+
Yarrow::Config::Instance.new(
|
59
|
+
output_dir: Pathname.new(File.expand_path(out_dir_or_string)),
|
60
|
+
source: Pathname.new(File.expand_path(source_dir_or_string)),
|
61
|
+
content: Pathname.new(File.expand_path(content_dir_or_string)),
|
62
|
+
meta: meta_obj,
|
63
|
+
server: server_obj
|
64
|
+
)
|
65
|
+
end
|
92
66
|
end
|
93
67
|
end
|
94
68
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
puts "CollectionExpander!!!"
|
2
|
-
|
3
1
|
module Yarrow
|
4
2
|
module Content
|
5
3
|
class CollectionExpander
|
@@ -127,7 +125,7 @@ module Yarrow
|
|
127
125
|
|
128
126
|
def build_content_nodes(graph, objects, type, parent_index)
|
129
127
|
# TODO: this may need to use a strategy that can be overriden
|
130
|
-
content_type =
|
128
|
+
content_type = Yarrow::Symbols.to_singular(type)
|
131
129
|
|
132
130
|
# Process collected content objects and generate entity nodes
|
133
131
|
objects.each do |name, sources|
|
@@ -174,8 +172,9 @@ module Yarrow
|
|
174
172
|
# TODO: consider whether to provide `body` on the item/document or at
|
175
173
|
# the custom content type level.
|
176
174
|
begin
|
177
|
-
content_struct =
|
175
|
+
content_struct = Yarrow::Symbols.to_const(content_type)
|
178
176
|
rescue
|
177
|
+
# No immutable struct found: fall back to slower dynamically typed open struct
|
179
178
|
require "ostruct"
|
180
179
|
content_struct = OpenStruct
|
181
180
|
end
|
@@ -1,10 +1,14 @@
|
|
1
|
+
gem "strings-inflection"
|
2
|
+
|
1
3
|
module Yarrow
|
2
4
|
module Content
|
3
5
|
class ContentType
|
6
|
+
Value = Yarrow::Schema::Value.new(:collection, :entity, :extensions)
|
7
|
+
|
4
8
|
DEFAULT_EXTENSIONS = [".md", ".yml", ".htm"]
|
5
9
|
|
6
10
|
def self.from_name(name)
|
7
|
-
new(
|
11
|
+
new(Value.new(collection: name.to_sym))
|
8
12
|
end
|
9
13
|
|
10
14
|
def initialize(properties)
|
@@ -16,17 +20,17 @@ module Yarrow
|
|
16
20
|
end
|
17
21
|
|
18
22
|
def collection
|
19
|
-
return @properties.collection if @properties.
|
20
|
-
|
23
|
+
return @properties.collection if @properties.collection
|
24
|
+
Yarrow::Symbols.to_plural(@properties.entity)
|
21
25
|
end
|
22
26
|
|
23
27
|
def entity
|
24
|
-
return @properties.entity if @properties.
|
25
|
-
|
28
|
+
return @properties.entity if @properties.entity
|
29
|
+
Yarrow::Symbols.to_singular(@properties.collection)
|
26
30
|
end
|
27
31
|
|
28
32
|
def extensions
|
29
|
-
return @properties.extensions if @properties.
|
33
|
+
return @properties.extensions if @properties.extensions
|
30
34
|
DEFAULT_EXTENSIONS
|
31
35
|
end
|
32
36
|
|
data/lib/yarrow/content/graph.rb
CHANGED
@@ -1,35 +1,10 @@
|
|
1
|
-
require "mementus"
|
2
|
-
|
3
|
-
module Mementus
|
4
|
-
module Pipeline
|
5
|
-
class Step
|
6
|
-
# Monkeypatch extension to ensure each pipeline step supports enumerable
|
7
|
-
# methods. Mostly used for #map. API needs to be fixed in the gem itself.
|
8
|
-
include Enumerable
|
9
|
-
end
|
10
|
-
end
|
11
|
-
module Structure
|
12
|
-
class IncidenceList
|
13
|
-
def inspect
|
14
|
-
"<Mementus::Structure::IncidenceList>"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
class Graph
|
19
|
-
def inspect
|
20
|
-
"<Mementus::Graph @structure=#{@structure.inspect} " +
|
21
|
-
"nodes_count=#{nodes_count} edges_count=#{edges_count}>"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
1
|
module Yarrow
|
27
2
|
module Content
|
28
3
|
# A directed graph of every element of content in the project.
|
29
4
|
class Graph
|
30
5
|
# Construct a graph collected from source content files.
|
31
6
|
def self.from_source(config)
|
32
|
-
new(SourceCollector.collect(config.
|
7
|
+
new(SourceCollector.collect(config.source), config)
|
33
8
|
end
|
34
9
|
|
35
10
|
attr_reader :graph, :config
|
@@ -40,7 +15,7 @@ module Yarrow
|
|
40
15
|
end
|
41
16
|
|
42
17
|
def expand_pages
|
43
|
-
expander = Yarrow::Content::CollectionExpander.new
|
18
|
+
expander = Yarrow::Content::CollectionExpander.new
|
44
19
|
expander.expand(graph)
|
45
20
|
end
|
46
21
|
|
@@ -0,0 +1 @@
|
|
1
|
+
require "yarrow/extensions/mementus"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "mementus"
|
2
|
+
|
3
|
+
module Mementus
|
4
|
+
module Pipeline
|
5
|
+
class Step
|
6
|
+
# Monkeypatch extension to ensure each pipeline step supports enumerable
|
7
|
+
# methods. Mostly used for #map. API needs to be fixed in the gem itself.
|
8
|
+
include Enumerable
|
9
|
+
end
|
10
|
+
end
|
11
|
+
module Structure
|
12
|
+
class IncidenceList
|
13
|
+
def inspect
|
14
|
+
"<Mementus::Structure::IncidenceList>"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
class Graph
|
19
|
+
def inspect
|
20
|
+
"<Mementus::Graph @structure=#{@structure.inspect} " +
|
21
|
+
"nodes_count=#{nodes_count} edges_count=#{edges_count}>"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,11 +4,7 @@ module Yarrow
|
|
4
4
|
#
|
5
5
|
# Methods provided by this class become available as named variables in
|
6
6
|
# Mustache templates.
|
7
|
-
#
|
8
|
-
# Includes the library of helpers for dynamically generating HTML tags.
|
9
7
|
class Context
|
10
|
-
include Yarrow::HTML::AssetTags
|
11
|
-
|
12
8
|
def initialize(attributes)
|
13
9
|
metaclass = class << self; self; end
|
14
10
|
attributes.each do |name, value|
|
@@ -8,12 +8,12 @@ module Yarrow
|
|
8
8
|
|
9
9
|
# Mapping between template types and provided object model
|
10
10
|
def object_map
|
11
|
-
@config
|
11
|
+
@config[:output][:object_map]
|
12
12
|
end
|
13
13
|
|
14
14
|
# Mapping between template types and provided output templates.
|
15
15
|
def template_map
|
16
|
-
|
16
|
+
|
17
17
|
end
|
18
18
|
|
19
19
|
# Template converter used by this generator instance.
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Yarrow
|
2
|
+
module Output
|
3
|
+
module Web
|
4
|
+
class IndexedFile
|
5
|
+
WRITE_MODE = 'w+:UTF-8'.freeze
|
6
|
+
|
7
|
+
# @return [String] Basename reflecting the server convention (usually: index.html)
|
8
|
+
def index_name
|
9
|
+
@index_name ||= config.index_name || 'index.html'
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [String] Docroot of the output target
|
13
|
+
def docroot
|
14
|
+
@docroot ||= config.output_dir || 'public'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Write an output file to the specified path under the docroot.
|
18
|
+
#
|
19
|
+
# @param path [String]
|
20
|
+
# @param content [String]
|
21
|
+
def write(path, content)
|
22
|
+
# If the target path is a directory,
|
23
|
+
# generate a default index filename.
|
24
|
+
if path[path.length-1] == '/'
|
25
|
+
path = "#{path}#{index_name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
target_path = Pathname.new("#{docroot}#{path}")
|
29
|
+
|
30
|
+
FileUtils.mkdir_p(target_path.dirname)
|
31
|
+
|
32
|
+
File.open(target_path.to_s, WRITE_MODE) do |file|
|
33
|
+
file.puts(content)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Yarrow
|
2
|
+
module Schema
|
3
|
+
module Type
|
4
|
+
class Any
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Checks values plugged into each slot and runs any required validations
|
10
|
+
# (validations not yet implemented).
|
11
|
+
#
|
12
|
+
# Current design throws on error rather than returns a boolean result.
|
13
|
+
class Validator
|
14
|
+
# @param fields_spec [Hash] defines the slots in the schema to validate against
|
15
|
+
def initialize(fields_spec)
|
16
|
+
@spec = fields_spec
|
17
|
+
end
|
18
|
+
|
19
|
+
def check(fields)
|
20
|
+
missing_fields = @spec.keys.difference(fields.keys)
|
21
|
+
|
22
|
+
if missing_fields.any?
|
23
|
+
missing_fields.each do |field|
|
24
|
+
raise "wrong number of args" unless @spec[field].eql?(Type::Any)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
mismatching_fields = fields.keys.difference(@spec.keys)
|
29
|
+
|
30
|
+
raise "key does not exist" if mismatching_fields.any?
|
31
|
+
|
32
|
+
fields.each do |(field, value)|
|
33
|
+
raise "wrong data type" unless value.is_a?(@spec[field]) || @spec[field].eql?(Type::Any)
|
34
|
+
end
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Value object (with comparison by value equality). This just chucks back a
|
42
|
+
# Ruby struct but wraps the constructor with method advice that handles
|
43
|
+
# validation (and eventually type coercion if !yagni).
|
44
|
+
class Value
|
45
|
+
def self.new(*slots, **fields, &block)
|
46
|
+
factory(*slots, **fields, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.factory(*slots, **fields, &block)
|
50
|
+
if slots.empty? && fields.empty?
|
51
|
+
raise ArgumentError.new("missing attribute definition")
|
52
|
+
end
|
53
|
+
|
54
|
+
slots_spec, fields_spec = if fields.any?
|
55
|
+
raise ArgumentError.new("cannot use slots when field map is supplied") if slots.any?
|
56
|
+
[fields.keys, fields]
|
57
|
+
else
|
58
|
+
[slots, Hash[slots.map { |s| [s, Type::Any]}]]
|
59
|
+
end
|
60
|
+
|
61
|
+
validator = Validator.new(fields_spec)
|
62
|
+
|
63
|
+
struct = Struct.new(*slots_spec, keyword_init: true, &block)
|
64
|
+
|
65
|
+
struct.define_method :initialize do |*args, **kwargs|
|
66
|
+
attr_values = if args.any?
|
67
|
+
raise ArgumentError.new("cannot mix slots and kwargs") if kwargs.any?
|
68
|
+
Hash[slots.zip(args)]
|
69
|
+
else
|
70
|
+
kwargs
|
71
|
+
end
|
72
|
+
|
73
|
+
validator.check(attr_values)
|
74
|
+
# TODO: type coercion or mapping decision goes here
|
75
|
+
super(**attr_values)
|
76
|
+
|
77
|
+
freeze
|
78
|
+
end
|
79
|
+
|
80
|
+
struct
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Entity with comparison by reference equality. Generates attribute helpers
|
86
|
+
# for a declared set of props. Used to replace Hashie::Mash without dragging
|
87
|
+
# in a whole new library.
|
88
|
+
class Entity
|
89
|
+
class << self
|
90
|
+
def attribute(name, value_type)
|
91
|
+
# define_method("map_#{name}".to_sym) do |input|
|
92
|
+
# value_type.coerce(input)
|
93
|
+
# end
|
94
|
+
dictionary[name] = value_type
|
95
|
+
attr_reader(name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def dictionary
|
99
|
+
@dictionary ||= Hash.new
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dictionary
|
104
|
+
self.class.dictionary
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize(config)
|
108
|
+
dictionary.each_key do |name|
|
109
|
+
raise "missing declared attribute #{name}" unless dictionary.key?(name)
|
110
|
+
end
|
111
|
+
|
112
|
+
config.each_pair do |key, value|
|
113
|
+
raise "#{key} not a declared attribute" unless dictionary.key?(key)
|
114
|
+
|
115
|
+
defined_type = dictionary[key]
|
116
|
+
|
117
|
+
unless value.is_a?(defined_type)
|
118
|
+
raise "#{key} accepts #{defined_type} but #{value.class} given"
|
119
|
+
end
|
120
|
+
|
121
|
+
instance_variable_set("@#{key}", value)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_h
|
127
|
+
dictionary.keys.reduce({}) do |h, name|
|
128
|
+
h[name] = instance_variable_get("@#{name}")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
data/lib/yarrow/server.rb
CHANGED
@@ -4,12 +4,14 @@ module Yarrow
|
|
4
4
|
##
|
5
5
|
# Little web server for browsing local files.
|
6
6
|
class Server
|
7
|
-
|
7
|
+
attr_reader :config
|
8
8
|
|
9
|
-
def initialize
|
10
|
-
if
|
11
|
-
raise ConfigurationError.new(
|
9
|
+
def initialize(instance_config)
|
10
|
+
if instance_config.server.nil?
|
11
|
+
raise ConfigurationError.new("Missing server entry")
|
12
12
|
end
|
13
|
+
|
14
|
+
@config = instance_config
|
13
15
|
end
|
14
16
|
|
15
17
|
##
|
@@ -98,7 +100,7 @@ module Yarrow
|
|
98
100
|
##
|
99
101
|
# @return [String]
|
100
102
|
def docroot
|
101
|
-
config.output_dir
|
103
|
+
config.output_dir
|
102
104
|
end
|
103
105
|
|
104
106
|
##
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "strings-inflection"
|
2
|
+
require "strings-case"
|
3
|
+
|
4
|
+
module Yarrow
|
5
|
+
module Symbols
|
6
|
+
# Converts an atomic content identifier to a live class constant.
|
7
|
+
def self.to_const(atom)
|
8
|
+
Object.const_get(Strings::Case.pascalcase(atom.to_s).to_sym)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.to_singular(atom)
|
12
|
+
Strings::Inflection.singularize(atom.to_s).to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.to_plural(atom)
|
16
|
+
Strings::Inflection.pluralize(atom.to_s).to_sym
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Yarrow
|
2
|
+
module Tools
|
3
|
+
# Synchronous utility functions for working with filesystem content tasks.
|
4
|
+
module ContentUtils
|
5
|
+
# Pass in a source path and get back a parsed representation of the
|
6
|
+
# content if it is in a known text format. Mostly used as a fallback if
|
7
|
+
# a custom parser or processing chain is not configured for a content
|
8
|
+
# type.
|
9
|
+
#
|
10
|
+
# Supported formats:
|
11
|
+
# - HTML template and document partials
|
12
|
+
# - Markdown documents
|
13
|
+
# - YAML documents
|
14
|
+
# - JSON (untested)
|
15
|
+
#
|
16
|
+
# Works around meta and content source in multiple files or a single
|
17
|
+
# file with front matter.
|
18
|
+
def read_yfm(name)
|
19
|
+
path = if name.is_a?(Pathname)
|
20
|
+
name
|
21
|
+
else
|
22
|
+
Pathname.new(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
text = File.read(path, :encoding => 'utf-8')
|
26
|
+
|
27
|
+
case path.extname
|
28
|
+
when '.htm', '.md', '.txt', '.yfm'
|
29
|
+
extract_yfm(text, symbolize_keys: true)
|
30
|
+
# when '.md'
|
31
|
+
# body, data = read_split_content(path.to_s, symbolize_keys: true)
|
32
|
+
# [Kramdown::Document.new(body).to_html, data]
|
33
|
+
when '.yml'
|
34
|
+
[nil, YAML.load(File.read(path.to_s), symbolize_names: true)]
|
35
|
+
when '.json'
|
36
|
+
[nil, JSON.parse(File.read(path.to_s))]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_yfm(text, options={})
|
41
|
+
pattern = /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
42
|
+
if text =~ pattern
|
43
|
+
content = text.sub(pattern, "")
|
44
|
+
|
45
|
+
begin
|
46
|
+
if options.key?(:symbolize_keys)
|
47
|
+
meta = YAML.load($1, symbolize_names: true)
|
48
|
+
else
|
49
|
+
meta = YAML.load($1)
|
50
|
+
end
|
51
|
+
return [content, meta]
|
52
|
+
rescue Psych::SyntaxError => error
|
53
|
+
if defined? ::Logger
|
54
|
+
# todo: application wide logger
|
55
|
+
#logger = ::Logger.new(STDOUT)
|
56
|
+
#logger.error "#{error.message}"
|
57
|
+
end
|
58
|
+
return [content, nil]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
[text, nil]
|
63
|
+
end
|
64
|
+
|
65
|
+
def write_yfm(name, text, meta)
|
66
|
+
# Symbolized keys are better to deal with when manipulating data in
|
67
|
+
# Ruby but are an interop nightmare when serialized so here we do a
|
68
|
+
# round-trip through JSON encoding to ensure all keys are string
|
69
|
+
# encoded before dumping them to the front matter format.
|
70
|
+
File.write(name, [YAML.dump(meta.to_json), "---", text].join("\n"))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Yarrow
|
2
2
|
module Tools
|
3
|
+
# @deprecated
|
4
|
+
# Maintained here as it is still used in a number of places but needs to be removed soon
|
3
5
|
module FrontMatter
|
4
6
|
|
5
7
|
def read_split_content(path, options={})
|
@@ -21,8 +23,8 @@ module Yarrow
|
|
21
23
|
rescue Psych::SyntaxError => error
|
22
24
|
if defined? ::Logger
|
23
25
|
# todo: application wide logger
|
24
|
-
logger = ::Logger.new(STDOUT)
|
25
|
-
logger.error "#{error.message}"
|
26
|
+
#logger = ::Logger.new(STDOUT)
|
27
|
+
#logger.error "#{error.message}"
|
26
28
|
end
|
27
29
|
return [content, nil]
|
28
30
|
end
|
data/lib/yarrow/version.rb
CHANGED
data/yarrow.gemspec
CHANGED
@@ -13,14 +13,13 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
14
14
|
spec.executables << 'yarrow'
|
15
15
|
spec.executables << 'yarrow-server'
|
16
|
-
spec.add_runtime_dependency 'hashie', '~> 3.5'
|
17
16
|
spec.add_runtime_dependency 'mementus', '~> 0.8'
|
18
|
-
spec.add_runtime_dependency 'activesupport', '~> 5.1'
|
19
17
|
spec.add_runtime_dependency 'rack', '~> 2.0'
|
20
18
|
spec.add_runtime_dependency 'rack-livereload', '~> 0.3'
|
21
19
|
spec.add_runtime_dependency 'eventmachine', '~> 1.2'
|
22
20
|
spec.add_runtime_dependency 'em-websocket', '~> 0.5.1'
|
23
|
-
spec.add_runtime_dependency '
|
21
|
+
spec.add_runtime_dependency 'strings-inflection', '~> 0.1'
|
22
|
+
spec.add_runtime_dependency 'strings-case', '~> 0.3'
|
24
23
|
spec.add_development_dependency 'bundler', '~> 2.2.9'
|
25
24
|
spec.add_development_dependency 'rake', '~> 13.0'
|
26
25
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yarrow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: hashie
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '3.5'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '3.5'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: mementus
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +24,6 @@ dependencies:
|
|
38
24
|
- - "~>"
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '0.8'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: activesupport
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '5.1'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '5.1'
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
28
|
name: rack
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,19 +81,33 @@ dependencies:
|
|
109
81
|
- !ruby/object:Gem::Version
|
110
82
|
version: 0.5.1
|
111
83
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
84
|
+
name: strings-inflection
|
113
85
|
requirement: !ruby/object:Gem::Requirement
|
114
86
|
requirements:
|
115
87
|
- - "~>"
|
116
88
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
89
|
+
version: '0.1'
|
118
90
|
type: :runtime
|
119
91
|
prerelease: false
|
120
92
|
version_requirements: !ruby/object:Gem::Requirement
|
121
93
|
requirements:
|
122
94
|
- - "~>"
|
123
95
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
96
|
+
version: '0.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: strings-case
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.3'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.3'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
112
|
name: bundler
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,6 +200,7 @@ files:
|
|
214
200
|
- lib/yarrow/assets.rb
|
215
201
|
- lib/yarrow/assets/manifest.rb
|
216
202
|
- lib/yarrow/assets/pipeline.rb
|
203
|
+
- lib/yarrow/config.rb
|
217
204
|
- lib/yarrow/configuration.rb
|
218
205
|
- lib/yarrow/console_runner.rb
|
219
206
|
- lib/yarrow/content/collection_expander.rb
|
@@ -223,25 +210,34 @@ files:
|
|
223
210
|
- lib/yarrow/content/source_collector.rb
|
224
211
|
- lib/yarrow/content_map.rb
|
225
212
|
- lib/yarrow/defaults.yml
|
213
|
+
- lib/yarrow/extensions.rb
|
214
|
+
- lib/yarrow/extensions/mementus.rb
|
226
215
|
- lib/yarrow/generator.rb
|
227
|
-
- lib/yarrow/html.rb
|
228
|
-
- lib/yarrow/html/asset_tags.rb
|
229
|
-
- lib/yarrow/html/content_tags.rb
|
230
216
|
- lib/yarrow/logging.rb
|
231
217
|
- lib/yarrow/output/context.rb
|
232
218
|
- lib/yarrow/output/generator.rb
|
233
219
|
- lib/yarrow/output/mapper.rb
|
220
|
+
- lib/yarrow/output/web/indexed_file.rb
|
234
221
|
- lib/yarrow/process/expand_content.rb
|
235
222
|
- lib/yarrow/process/extract_source.rb
|
236
223
|
- lib/yarrow/process/project_manifest.rb
|
237
224
|
- lib/yarrow/process/step_processor.rb
|
238
225
|
- lib/yarrow/process/workflow.rb
|
226
|
+
- lib/yarrow/schema.rb
|
227
|
+
- lib/yarrow/schema/validations/array.rb
|
228
|
+
- lib/yarrow/schema/validations/object.rb
|
229
|
+
- lib/yarrow/schema/validations/string.rb
|
239
230
|
- lib/yarrow/server.rb
|
240
231
|
- lib/yarrow/server/livereload.rb
|
241
232
|
- lib/yarrow/source/graph.rb
|
233
|
+
- lib/yarrow/symbols.rb
|
234
|
+
- lib/yarrow/tools/content_utils.rb
|
242
235
|
- lib/yarrow/tools/front_matter.rb
|
243
|
-
- lib/yarrow/tools/output_file.rb
|
244
236
|
- lib/yarrow/version.rb
|
237
|
+
- lib/yarrow/web/html_document.rb
|
238
|
+
- lib/yarrow/web/manifest.rb
|
239
|
+
- lib/yarrow/web/static_asset.rb
|
240
|
+
- lib/yarrow/web/template.rb
|
245
241
|
- yarrow.gemspec
|
246
242
|
homepage: http://rubygemspec.org/gems/yarrow
|
247
243
|
licenses:
|
data/lib/yarrow/html.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require_relative 'html/asset_tags'
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module Yarrow
|
2
|
-
module HTML
|
3
|
-
module AssetTags
|
4
|
-
include Yarrow::Configurable
|
5
|
-
|
6
|
-
# TODO: make sprockets manifest optional/pluggable
|
7
|
-
def manifest
|
8
|
-
Yarrow::Assets::Manifest.new(config)
|
9
|
-
end
|
10
|
-
|
11
|
-
##
|
12
|
-
# Computes the base URL path to assets in the public web directory.
|
13
|
-
def base_url_path
|
14
|
-
if config.assets.nil? || config.output_dir.nil?
|
15
|
-
raise Yarrow::ConfigurationError
|
16
|
-
end
|
17
|
-
|
18
|
-
# TODO: prepend configurable CDN URL for host path
|
19
|
-
# TODO: dev/production mode switch
|
20
|
-
|
21
|
-
config.assets.output_dir.gsub(config.output_dir, '')
|
22
|
-
end
|
23
|
-
|
24
|
-
def script_tags
|
25
|
-
manifest.js_logical_paths.map { |path| script_tag(asset: path) }.join("\n")
|
26
|
-
end
|
27
|
-
|
28
|
-
def script_tag(options)
|
29
|
-
src_path = if asset_in_manifest?(options)
|
30
|
-
digest_path(options[:asset])
|
31
|
-
else
|
32
|
-
options[:src]
|
33
|
-
end
|
34
|
-
|
35
|
-
"<script src=\"#{src_path}\"></script>"
|
36
|
-
end
|
37
|
-
|
38
|
-
def link_tag(options)
|
39
|
-
href_path = if asset_in_manifest?(options)
|
40
|
-
digest_path(options[:asset])
|
41
|
-
else
|
42
|
-
options[:href]
|
43
|
-
end
|
44
|
-
|
45
|
-
"<link href=\"#{href_path}\" rel=\"stylesheet\" type=\"text/css\">"
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def asset_in_manifest?(options)
|
51
|
-
options.has_key?(:asset) and manifest.exists?(options[:asset])
|
52
|
-
end
|
53
|
-
|
54
|
-
def digest_path(path)
|
55
|
-
"#{base_url_path}/#{manifest.digest_path(path)}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Yarrow
|
2
|
-
module Tools
|
3
|
-
# TODO: consider renaming this to OutputDocument.
|
4
|
-
class OutputFile
|
5
|
-
include Yarrow::Configurable
|
6
|
-
|
7
|
-
WRITE_MODE = 'w+:UTF-8'.freeze
|
8
|
-
|
9
|
-
# @return [String] Basename reflecting the server convention (usually: index.html)
|
10
|
-
def index_name
|
11
|
-
@index_name ||= config.index_name || 'index.html'
|
12
|
-
end
|
13
|
-
|
14
|
-
# @return [String] Docroot of the output target
|
15
|
-
def docroot
|
16
|
-
@docroot ||= config.output_dir || 'public'
|
17
|
-
end
|
18
|
-
|
19
|
-
# Write an output file to the specified path under the docroot.
|
20
|
-
#
|
21
|
-
# @param path [String]
|
22
|
-
# @param content [String]
|
23
|
-
def write(path, content)
|
24
|
-
# If the target path is a directory,
|
25
|
-
# generate a default index filename.
|
26
|
-
if path[path.length-1] == '/'
|
27
|
-
path = "#{path}#{index_name}"
|
28
|
-
end
|
29
|
-
|
30
|
-
target_path = Pathname.new("#{docroot}#{path}")
|
31
|
-
|
32
|
-
FileUtils.mkdir_p(target_path.dirname)
|
33
|
-
|
34
|
-
File.open(target_path.to_s, WRITE_MODE) do |file|
|
35
|
-
file.puts(content)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|