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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.cane +4 -0
  3. data/.gitignore +17 -0
  4. data/.rspec +5 -0
  5. data/.travis.yml +34 -0
  6. data/.yardopts +1 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile-jruby +4 -0
  9. data/LICENSE.md +22 -0
  10. data/README.md +50 -0
  11. data/Rakefile +61 -0
  12. data/bin/usmu +10 -0
  13. data/cucumber.yml +2 -0
  14. data/lib/usmu.rb +12 -0
  15. data/lib/usmu/configuration.rb +83 -0
  16. data/lib/usmu/layout.rb +166 -0
  17. data/lib/usmu/page.rb +19 -0
  18. data/lib/usmu/site_generator.rb +82 -0
  19. data/lib/usmu/static_file.rb +39 -0
  20. data/lib/usmu/ui.rb +7 -0
  21. data/lib/usmu/ui/console.rb +26 -0
  22. data/lib/usmu/version.rb +5 -0
  23. data/test/expected-site/default.html +3 -0
  24. data/test/expected-site/embedded.html +15 -0
  25. data/test/expected-site/index.html +14 -0
  26. data/test/expected-site/robots.txt +1 -0
  27. data/test/features/generator.feature +10 -0
  28. data/test/features/step_definitions/step_general.rb +18 -0
  29. data/test/site/content/default.md +3 -0
  30. data/test/site/content/embedded.md +1 -0
  31. data/test/site/content/embedded.meta.yml +2 -0
  32. data/test/site/content/index.md +3 -0
  33. data/test/site/content/index.meta.yml +3 -0
  34. data/test/site/content/robots.txt +1 -0
  35. data/test/site/layouts/embedded.meta.yml +2 -0
  36. data/test/site/layouts/embedded.slim +2 -0
  37. data/test/site/layouts/html.meta.yml +2 -0
  38. data/test/site/layouts/html.slim +8 -0
  39. data/test/site/usmu.yml +15 -0
  40. data/test/spec/configuration_spec.rb +51 -0
  41. data/test/spec/layout_spec.rb +27 -0
  42. data/test/spec/page_spec.rb +15 -0
  43. data/test/spec/site_generator_spec.rb +32 -0
  44. data/test/spec/spec_helper.rb +85 -0
  45. data/test/spec/static_file_spec.rb +20 -0
  46. data/test/spec/support/shared_layout.rb +111 -0
  47. data/usmu-jruby.gemspec +34 -0
  48. data/usmu.gemspec +35 -0
  49. metadata +291 -0
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'usmu'
2
+
3
+ module Usmu
4
+ # This module is for all the different UI's. If you implement a custom UI it should be added here.
5
+ module Ui
6
+ end
7
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+
2
+ module Usmu
3
+ # The current versions string for the gem
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,3 @@
1
+ <h1>Default output</h1>
2
+
3
+ <p>No metadata for this file. Uh oh!</p>
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Default Title | Testing website</title>
5
+ </head>
6
+ <body>
7
+ <div id="content">
8
+ <div class="embedded">
9
+ <h1>Embedded test</h1>
10
+
11
+ </div>
12
+
13
+ </div>
14
+ </body>
15
+ </html>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Default Title | Testing website</title>
5
+ </head>
6
+ <body>
7
+ <div id="content">
8
+ <h1>Test index</h1>
9
+
10
+ <p>This is some test content</p>
11
+
12
+ </div>
13
+ </body>
14
+ </html>
@@ -0,0 +1 @@
1
+ User-agent: *
@@ -0,0 +1,10 @@
1
+
2
+ Feature:
3
+ In order to create a website
4
+ As a user
5
+ I would like to generate a static website
6
+
7
+ Scenario:
8
+ Given I have a site at "test/site"
9
+ When I generate the site
10
+ Then the destination directory should match "test/expected-site"
@@ -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,3 @@
1
+ # Default output
2
+
3
+ No metadata for this file. Uh oh!
@@ -0,0 +1 @@
1
+ # Embedded test
@@ -0,0 +1,2 @@
1
+ ---
2
+ layout: embedded
@@ -0,0 +1,3 @@
1
+ # Test index
2
+
3
+ This is some test content
@@ -0,0 +1,3 @@
1
+ ---
2
+ title: Index page
3
+ layout: html
@@ -0,0 +1 @@
1
+ User-agent: *
@@ -0,0 +1,2 @@
1
+ ---
2
+ layout: html
@@ -0,0 +1,2 @@
1
+ .embedded
2
+ | #{{content}}
@@ -0,0 +1,2 @@
1
+ ---
2
+ title: Default Title
@@ -0,0 +1,8 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title #{title} | #{site['title']}
5
+
6
+ body
7
+ #content
8
+ | #{{content}}
@@ -0,0 +1,15 @@
1
+ ---
2
+
3
+ source: content
4
+ destination: site
5
+ title: Testing website
6
+
7
+ default meta:
8
+ title: Test website
9
+ layout: html
10
+
11
+ slim:
12
+ :pretty: true
13
+
14
+ kramdown:
15
+ :auto_ids: false
@@ -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