usmu 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.cane +4 -0
- data/.gitignore +17 -0
- data/.rspec +5 -0
- data/.travis.yml +34 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/Gemfile-jruby +4 -0
- data/LICENSE.md +22 -0
- data/README.md +50 -0
- data/Rakefile +61 -0
- data/bin/usmu +10 -0
- data/cucumber.yml +2 -0
- data/lib/usmu.rb +12 -0
- data/lib/usmu/configuration.rb +83 -0
- data/lib/usmu/layout.rb +166 -0
- data/lib/usmu/page.rb +19 -0
- data/lib/usmu/site_generator.rb +82 -0
- data/lib/usmu/static_file.rb +39 -0
- data/lib/usmu/ui.rb +7 -0
- data/lib/usmu/ui/console.rb +26 -0
- data/lib/usmu/version.rb +5 -0
- data/test/expected-site/default.html +3 -0
- data/test/expected-site/embedded.html +15 -0
- data/test/expected-site/index.html +14 -0
- data/test/expected-site/robots.txt +1 -0
- data/test/features/generator.feature +10 -0
- data/test/features/step_definitions/step_general.rb +18 -0
- data/test/site/content/default.md +3 -0
- data/test/site/content/embedded.md +1 -0
- data/test/site/content/embedded.meta.yml +2 -0
- data/test/site/content/index.md +3 -0
- data/test/site/content/index.meta.yml +3 -0
- data/test/site/content/robots.txt +1 -0
- data/test/site/layouts/embedded.meta.yml +2 -0
- data/test/site/layouts/embedded.slim +2 -0
- data/test/site/layouts/html.meta.yml +2 -0
- data/test/site/layouts/html.slim +8 -0
- data/test/site/usmu.yml +15 -0
- data/test/spec/configuration_spec.rb +51 -0
- data/test/spec/layout_spec.rb +27 -0
- data/test/spec/page_spec.rb +15 -0
- data/test/spec/site_generator_spec.rb +32 -0
- data/test/spec/spec_helper.rb +85 -0
- data/test/spec/static_file_spec.rb +20 -0
- data/test/spec/support/shared_layout.rb +111 -0
- data/usmu-jruby.gemspec +34 -0
- data/usmu.gemspec +35 -0
- metadata +291 -0
data/lib/usmu/page.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
module Usmu
|
|
3
|
+
# Represents a page in the source directory of the website.
|
|
4
|
+
class Page < Layout
|
|
5
|
+
protected
|
|
6
|
+
|
|
7
|
+
# @!attribute [r] content_path
|
|
8
|
+
# @return [string] the base path to the files used by this class.
|
|
9
|
+
#
|
|
10
|
+
# Returns the base path to the files used by this class.
|
|
11
|
+
#
|
|
12
|
+
# This folder should be the parent folder for the file named by the name attribute.
|
|
13
|
+
#
|
|
14
|
+
# @see #name
|
|
15
|
+
def content_path
|
|
16
|
+
@configuration.source_path
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Usmu
|
|
4
|
+
# This is the class that brings everything together to generate a new website.
|
|
5
|
+
class SiteGenerator
|
|
6
|
+
# @param [Usmu::Configuration] configuration The configuration to use for generating the website
|
|
7
|
+
def initialize(configuration)
|
|
8
|
+
@configuration = configuration
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @!attribute [r] layouts
|
|
12
|
+
# @return [Array<Usmu::Layout>] a list of layouts available in this website.
|
|
13
|
+
def layouts
|
|
14
|
+
get_renderables @configuration.layouts_path, true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @!attribute [r] renderables
|
|
18
|
+
# @return [Array<Usmu::StaticFile>] a list of renderable files from the source folder.
|
|
19
|
+
# will be a subclass of this class.
|
|
20
|
+
# @see Usmu::StaticFile
|
|
21
|
+
#
|
|
22
|
+
# Returns a list of renderable files from the source folder.
|
|
23
|
+
#
|
|
24
|
+
# The only guarantee made for individual files is that they will conform to the interface defined by
|
|
25
|
+
# Usmu::StaticFile and thus be renderable, however most files will be one of the subclasses of that class.
|
|
26
|
+
def renderables
|
|
27
|
+
get_renderables @configuration.source_path, false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @!attribute [r] pages
|
|
31
|
+
# @return [Array<Usmu::Page>] a list of pages from the source folder. This is any file in the source folder which
|
|
32
|
+
# is not static.
|
|
33
|
+
def pages
|
|
34
|
+
renderables.select {|r| r.class.name != 'Usmu::StaticFile'}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @!attribute [r] files
|
|
38
|
+
# @return [Array<Usmu::StaticFile>] a list of static files from the source folder.
|
|
39
|
+
def files
|
|
40
|
+
renderables.select {|r| r.class.name == 'Usmu::StaticFile'}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Generate the website according to the configuration given.
|
|
44
|
+
#
|
|
45
|
+
# @return [void]
|
|
46
|
+
def generate
|
|
47
|
+
renderables.each do |page|
|
|
48
|
+
file = File.join(@configuration.destination_path, page.output_filename)
|
|
49
|
+
directory = File.dirname(file)
|
|
50
|
+
|
|
51
|
+
unless File.directory?(directory)
|
|
52
|
+
FileUtils.mkdir_p(directory)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
File.write file, page.render
|
|
56
|
+
end
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# Helper function to search a directory recursively and return a list of files that are renderable.
|
|
63
|
+
#
|
|
64
|
+
# @param [String] directory the directory to search
|
|
65
|
+
# @param [Boolean] layout is this directory a layouts_path
|
|
66
|
+
# @return [Array<Usmu::Layout>, Array<Usmu::StaticFile>] Either an array of Layouts or StaticFiles in the directory
|
|
67
|
+
def get_renderables(directory, layout)
|
|
68
|
+
Dir["#{directory}/**/*"].select {|f| !f.match(/\.meta.yml$/) }.map do |f|
|
|
69
|
+
filename = f[(directory.length + 1)..f.length]
|
|
70
|
+
if layout
|
|
71
|
+
Usmu::Layout.new(@configuration, filename)
|
|
72
|
+
else
|
|
73
|
+
if Usmu::Layout.is_valid_file? 'source', filename
|
|
74
|
+
Usmu::Page.new(@configuration, filename)
|
|
75
|
+
else
|
|
76
|
+
Usmu::StaticFile.new(@configuration, filename)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
module Usmu
|
|
3
|
+
# Represents a static file which should be transferred to the destination unchanged. This also acts as the base
|
|
4
|
+
# class for all layouts and page types. The basic interface defined here is used to process all types of files.
|
|
5
|
+
class StaticFile
|
|
6
|
+
# @!attribute [r] name
|
|
7
|
+
# @return [String] the name of the file in the source directory
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
# @param configuration [Usmu::Configuration] The configuration for the website we're generating.
|
|
11
|
+
# @param name [String] The name of the file in the source directory.
|
|
12
|
+
# @param type [String] The type of template to use with the file. Not used for StaticFile.
|
|
13
|
+
# Used for testing purposes.
|
|
14
|
+
# @param content [String] The content of the file. Used for testing purposes.
|
|
15
|
+
# @param metadata [String] The metadata for the file. Used for testing purposes.
|
|
16
|
+
def initialize(configuration, name, type = nil, content = nil, metadata = nil)
|
|
17
|
+
@configuration = configuration
|
|
18
|
+
@name = name
|
|
19
|
+
@type = type
|
|
20
|
+
@content = content
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Renders the file with any templating language required and returns the result
|
|
24
|
+
#
|
|
25
|
+
# @param variables [Hash] Variables to be used in the template.
|
|
26
|
+
# @return [String] The rendered file
|
|
27
|
+
def render(variables = {})
|
|
28
|
+
@content || File.read(File.join(@configuration.source_path, @name))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @!attribute [r] output_filename
|
|
32
|
+
# @return [String] the filename to use in the output directory.
|
|
33
|
+
#
|
|
34
|
+
# Returns the filename to use for the output directory with any modifications to the input filename required.
|
|
35
|
+
def output_filename
|
|
36
|
+
@name
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/usmu/ui.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'usmu'
|
|
2
|
+
require 'trollop'
|
|
3
|
+
|
|
4
|
+
module Usmu
|
|
5
|
+
module Ui
|
|
6
|
+
# This is the CLI UI controller. This is initialised by the usmu binary to control the generation process.
|
|
7
|
+
class Console
|
|
8
|
+
# @!attribute [r] configuration
|
|
9
|
+
# @return [Usmu::Configuration] the configuration for the site we will generate.
|
|
10
|
+
attr_reader :configuration
|
|
11
|
+
|
|
12
|
+
# @param [Array<String>] args Command line arguments. Typically ARGV should be passed here.
|
|
13
|
+
def initialize(args)
|
|
14
|
+
@args = args
|
|
15
|
+
@configuration = Usmu::Configuration.from_file(File.join(args[0] || '.', 'usmu.yml'))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# This will run the command as setup in `#initialize`
|
|
19
|
+
#
|
|
20
|
+
# @return [void]
|
|
21
|
+
def execute
|
|
22
|
+
Usmu::SiteGenerator.new(@configuration).generate
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/usmu/version.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
User-agent: *
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'usmu/ui/console'
|
|
2
|
+
require 'open3'
|
|
3
|
+
|
|
4
|
+
Given(/^I have a site at "([^"]*)"$/) do |location|
|
|
5
|
+
@site = Usmu::Ui::Console.new([location])
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
When(/^I generate the site$/) do
|
|
9
|
+
@site.execute
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Then(/^the destination directory should match "([^"]*)"$/) do |test_folder|
|
|
13
|
+
run = %W{diff -qr #{@site.configuration.destination_path} #{test_folder}}
|
|
14
|
+
Open3.popen2e(*run) do |i, o, t|
|
|
15
|
+
output = run.join(' ') + "\n" + o.read
|
|
16
|
+
fail output if t.value != 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Embedded test
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
User-agent: *
|
data/test/site/usmu.yml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
require 'usmu/configuration'
|
|
3
|
+
|
|
4
|
+
RSpec.describe Usmu::Configuration do
|
|
5
|
+
context 'should prepend configuration folder' do
|
|
6
|
+
before do
|
|
7
|
+
hash = {
|
|
8
|
+
'source' => 'source',
|
|
9
|
+
'destination' => 'destination',
|
|
10
|
+
'layouts' => 'templates',
|
|
11
|
+
}
|
|
12
|
+
@configuration = Usmu::Configuration.from_hash(hash, 'test/usmu.yaml')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'to source' do
|
|
16
|
+
expect(@configuration.source_path).to eq('test/source')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'to destination' do
|
|
20
|
+
expect(@configuration.destination_path).to eq('test/destination')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'to layouts' do
|
|
24
|
+
expect(@configuration.layouts_path).to eq('test/templates')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'should have a default path' do
|
|
29
|
+
before do
|
|
30
|
+
hash = {}
|
|
31
|
+
@configuration = Usmu::Configuration.from_hash(hash)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'for source' do
|
|
35
|
+
expect(@configuration.source_path).to eq('src')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'for destination' do
|
|
39
|
+
expect(@configuration.destination_path).to eq('site')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'for layouts' do
|
|
43
|
+
expect(@configuration.layouts_path).to eq('layouts')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'should remember arbitrary configuration' do
|
|
48
|
+
configuration = Usmu::Configuration.from_hash({:test => 'foo'})
|
|
49
|
+
expect(configuration[:test]).to eq('foo')
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
require 'support/shared_layout'
|
|
3
|
+
require 'usmu/layout'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Usmu::Layout do
|
|
6
|
+
it_behaves_like 'an embeddable layout'
|
|
7
|
+
|
|
8
|
+
let(:configuration) { Usmu::Configuration.from_file('test/site/usmu.yml') }
|
|
9
|
+
|
|
10
|
+
it 'uses the \'layouts\' folder' do
|
|
11
|
+
layout = Usmu::Layout.new(configuration, 'html.slim')
|
|
12
|
+
rendered = layout.render({'content' => 'test'})
|
|
13
|
+
expect(rendered).to eq(<<-EOF)
|
|
14
|
+
<!DOCTYPE html>
|
|
15
|
+
<html>
|
|
16
|
+
<head>
|
|
17
|
+
<title>Default Title | Testing website</title>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<div id="content">
|
|
21
|
+
test
|
|
22
|
+
</div>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
25
|
+
EOF
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
require 'support/shared_layout'
|
|
3
|
+
require 'usmu/page'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Usmu::Page do
|
|
6
|
+
it_behaves_like 'an embeddable layout'
|
|
7
|
+
|
|
8
|
+
let(:configuration) { Usmu::Configuration.from_file('test/site/usmu.yml') }
|
|
9
|
+
|
|
10
|
+
it 'uses the \'source\' folder' do
|
|
11
|
+
page = Usmu::Page.new(configuration, 'index.md')
|
|
12
|
+
rendered = page.render({})
|
|
13
|
+
expect(rendered).to eq(File.read('test/expected-site/index.html'))
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
require 'usmu/site_generator'
|
|
3
|
+
|
|
4
|
+
RSpec.describe Usmu::SiteGenerator do
|
|
5
|
+
let(:configuration) { Usmu::Configuration.from_file('test/site/usmu.yml') }
|
|
6
|
+
let(:generator) { Usmu::SiteGenerator.new(configuration) }
|
|
7
|
+
|
|
8
|
+
it 'should have layouts' do
|
|
9
|
+
expect(generator.respond_to? :layouts).to eq(true)
|
|
10
|
+
expect(generator.layouts.map {|l| l.name}.sort).to eq(%w{embedded.slim html.slim})
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should have a list of renderable items' do
|
|
14
|
+
expect(generator.respond_to? :renderables).to eq(true)
|
|
15
|
+
expect(generator.renderables.map {|r| r.name}.sort).to eq(%w{default.md embedded.md index.md robots.txt})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should have pages' do
|
|
19
|
+
expect(generator.respond_to? :pages).to eq(true)
|
|
20
|
+
expect(generator.pages.map {|p| p.name}.sort).to eq(%w{default.md embedded.md index.md})
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should have files' do
|
|
24
|
+
expect(generator.respond_to? :files).to eq(true)
|
|
25
|
+
expect(generator.files.map {|f| f.name}.sort).to eq(%w{robots.txt})
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should be able to generate a site' do
|
|
29
|
+
expect(generator.respond_to? :generate).to eq(true)
|
|
30
|
+
# Further testing is exercised at the system integration level in the cukes.
|
|
31
|
+
end
|
|
32
|
+
end
|