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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2ce1d8bd5d6466dc1d6a3fd7bee6e296e53dc14
4
+ data.tar.gz: 9bc408aade4f29424ab873ec38ba4efef844b9ec
5
+ SHA512:
6
+ metadata.gz: adfea26ea6f7bc59ae8e95f7eaf9a3e795b40744933e6321fe2dacc2be4fa23f1dc38273edba618e6a80901c75ccc880ee3cda095f0667f1e96a48a7016c68b0
7
+ data.tar.gz: 9189d6c6248807abc95bd2c02b02f324b56eb89d99740565aac15b5339f6b2fc7e4586dd21c12cc9045321fdb18d456f285fd26fcd3d54c6b80a6976fcee48d2
data/.cane ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --max-violations 0
3
+ --style-measure 120
4
+ --abc-exclude Usmu::Layout#initialize
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile*.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ # Generated test site
17
+ /test/site/site
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --color
2
+ -I test/spec
3
+ --require spec_helper
4
+ --format documentation
5
+ --no-profile
@@ -0,0 +1,34 @@
1
+ language: ruby
2
+ script: rake ci
3
+ rvm:
4
+ - 2.0
5
+ - 2.1
6
+ - ruby-head
7
+ - jruby-19mode
8
+ - jruby-head
9
+ - rbx-2
10
+ - rbx-head
11
+ gemfile:
12
+ - Gemfile
13
+ - Gemfile-jruby
14
+ matrix:
15
+ exclude:
16
+ - rvm: 2.0
17
+ gemfile: Gemfile-jruby
18
+ - rvm: 2.1
19
+ gemfile: Gemfile-jruby
20
+ - rvm: ruby-head
21
+ gemfile: Gemfile-jruby
22
+ - rvm: jruby-19mode
23
+ gemfile: Gemfile
24
+ - rvm: jruby-head
25
+ gemfile: Gemfile
26
+ - rvm: rbx-2
27
+ gemfile: Gemfile-jruby
28
+ - rvm: rbx-head
29
+ gemfile: Gemfile-jruby
30
+ allow_failures:
31
+ - rvm: jruby-19mode
32
+ - rvm: jruby-head
33
+ - rvm: rbx-2
34
+ - rvm: rbx-head
@@ -0,0 +1 @@
1
+ --private --protected --hide-void-return -m markdown -M redcarpet lib/**/*.rb - README.md
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in usmu.gemspec
4
+ gemspec name: 'usmu'
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in usmu.gemspec
4
+ gemspec name: 'usmu-jruby'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Matthew Scharley and contributors
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # usmu [![Build Status](https://travis-ci.org/usmu/usmu.svg?branch=master)](https://travis-ci.org/usmu/usmu)
2
+
3
+ **Source:** [https://github.com/usmu/usmu](https://github.com/usmu/usmu)
4
+ **Author:** Matthew Scharley
5
+ **Contributors:** [See contributors on GitHub][gh-contrib]
6
+ **Bugs/Support:** [Github Issues][gh-issues]
7
+ **Copyright:** 2014
8
+ **License:** [MIT license][license]
9
+ **Status:** Active
10
+
11
+ ## Synopsis
12
+
13
+ `usmu` is a static site generator intended to be used with the future Rails-based editing platform. It can also be used
14
+ to generate locally if you don't wish to use the web-based editor.
15
+
16
+ ## Installation
17
+
18
+ $ gem install usmu
19
+
20
+ ## Usage
21
+
22
+ TODO: Write usage instructions here
23
+
24
+ ## Compatibility
25
+
26
+ As a baseline `usmu` will pull in Slim for layouts and Redcarpet for content written in Markdown. However we use the
27
+ Tilt API to render all layouts and content, therefore you should be able to use anything supported by Tilt including
28
+ Sass, Less, Textile and [many others][tilt-support], you just need to ensure you have the correct gems installed.
29
+
30
+ If you want to further [configure the way your template's are processed][template-options] then you can specify
31
+ configurations for each template engine. Just add it to your `usmu.yml`:
32
+
33
+ ```yaml
34
+ slim:
35
+ :pretty: true
36
+ ```
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create a new Pull Request
45
+
46
+ [gh-contrib]: https://github.com/usmu/usmu/graphs/contributors
47
+ [gh-issues]: https://github.com/usmu/usmu/issues
48
+ [license]: https://github.com/usmu/usmu/blob/master/LICENSE.md
49
+ [tilt-support]: https://github.com/rtomayko/tilt/blob/master/README.md
50
+ [template-options]: https://github.com/rtomayko/tilt/blob/master/docs/TEMPLATES.md
@@ -0,0 +1,61 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ require 'usmu/version'
8
+
9
+ def current_gems
10
+ Dir["pkg/usmu-#{Usmu::VERSION}*.gem"]
11
+ end
12
+
13
+ RSpec::Core::RakeTask.new(:spec) do |t|
14
+ t.pattern = 'test/spec/**/*_spec.rb'
15
+ end
16
+
17
+ Cucumber::Rake::Task.new(:features) do |t|
18
+ t.cucumber_opts = 'test/features'
19
+ end
20
+
21
+ desc 'Run all test scripts'
22
+ task :test => [:clean, :spec, :features]
23
+
24
+ desc 'Run CI test suite'
25
+ task :ci => [:test]
26
+
27
+ desc 'Clean up after tests'
28
+ task :clean do
29
+ rm_r 'test/site/site' if File.exist? 'test/site/site'
30
+ current_gems.each {|f| rm f }
31
+ end
32
+
33
+ namespace :gem do
34
+ desc 'Build gems'
35
+ task :build => [:clean] do
36
+ mkdir 'pkg' unless File.exist? 'pkg'
37
+ Dir['*.gemspec'].each do |gemspec|
38
+ sh "gem build #{gemspec}"
39
+ end
40
+ Dir['*.gem'].each do |gem|
41
+ mv gem, "pkg/#{gem}"
42
+ end
43
+ end
44
+
45
+ desc 'Install gem'
46
+ task :install => ['gem:build'] do
47
+ if RUBY_PLATFORM == 'java'
48
+ sh "gem install pkg/usmu-#{Usmu::VERSION}-java.gem"
49
+ else
50
+ sh "gem install pkg/usmu-#{Usmu::VERSION}.gem"
51
+ end
52
+ end
53
+
54
+ desc 'Deploy gems to rubygems'
55
+ task :deploy => ['gem:build'] do
56
+ current_gems.each do |gem|
57
+ sh "gem push #{gem}"
58
+ end
59
+ sh "git tag #{Usmu::VERSION}" if File.exist? '.git'
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'usmu/ui/console'
5
+ rescue LoadError
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'usmu/ui/console'
8
+ end
9
+
10
+ Usmu::Ui::Console.new(ARGV).execute
@@ -0,0 +1,2 @@
1
+ ---
2
+ default: test/features --format pretty
@@ -0,0 +1,12 @@
1
+ %W{
2
+ usmu/version
3
+ usmu/configuration
4
+ usmu/static_file
5
+ usmu/layout
6
+ usmu/page
7
+ usmu/site_generator
8
+ }.each { |f| require f }
9
+
10
+ # This module contains all the code for the Usmu site generator
11
+ module Usmu
12
+ end
@@ -0,0 +1,83 @@
1
+ require 'yaml'
2
+
3
+ module Usmu
4
+ # This class is used to represent a configuration file. This file should be a YAML file and called `usmu.yml`
5
+ # by default.
6
+ class Configuration
7
+ # @!attribute [r] config_file
8
+ # @return [String] the name of the file used to load the configuration.
9
+ attr_reader :config_file
10
+ # @!attribute [r] config_file
11
+ # @return [String] the folder that the configuration was loaded from.
12
+ attr_reader :config_dir
13
+
14
+ # Load a configuration from a YAML file on disk.
15
+ #
16
+ # @return [Usmu::Configuration]
17
+ def self.from_file(filename)
18
+ from_hash(YAML.load_file(filename), filename)
19
+ end
20
+
21
+ # Load a configuration from a hash.
22
+ #
23
+ # @return [Usmu::Configuration]
24
+ def self.from_hash(hash, config_path = nil)
25
+ self.new(hash, config_path)
26
+ end
27
+
28
+ # @!attribute [r] source_path
29
+ # @return [String] the full path to the source folder
30
+ def source_path
31
+ get_path @config['source'] || 'src'
32
+ end
33
+
34
+ # @!attribute [r] destination_path
35
+ # @return [String] the full path to the destination folder
36
+ def destination_path
37
+ get_path @config['destination'] || 'site'
38
+ end
39
+
40
+ # @!attribute [r] layouts_path
41
+ # @return [String] the full path to the layouts folder
42
+ def layouts_path
43
+ get_path @config['layouts'] || 'layouts'
44
+ end
45
+
46
+ # An index accessor to directly access the configuration file. It should be noted that `['source']` and
47
+ # `#source_path` and other similar pairs will have different values. `['source']` is the raw value from the
48
+ # configuration file while the latter is a path on the system, potentially altered by the path from the current
49
+ # working directory to the configuration file and other factors. The accessor functions such as `#source_path`
50
+ # should be preferred for most usages.
51
+ #
52
+ # @param [String, Symbol] index The index to return.
53
+ # @return [Array, Hash, String, Symbol] Returns a value from the hash loaded from YAML. The type of value will
54
+ # ultimately depend on the configuration file and the index provided.
55
+ def [](index)
56
+ @config[index]
57
+ end
58
+
59
+ private
60
+
61
+ # This class has a private constructor.
62
+ #
63
+ # @see Usmu::Configuration.from_file
64
+ # @see Usmu::Configuration.from_hash
65
+ def initialize(hash, config_path)
66
+ @config = hash
67
+ @config_file = config_path
68
+ @config_dir = config_path ? File.dirname(config_path) : nil
69
+ end
70
+
71
+ # Helper function to transform a relative path in the configuration file to a relative path from the current
72
+ # working directory.
73
+ #
74
+ # @return [String]
75
+ def get_path(path)
76
+ if @config_dir.nil?
77
+ path
78
+ else
79
+ File.join(@config_dir, path)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,166 @@
1
+ require 'tilt'
2
+ require 'deep_merge'
3
+ require 'usmu/static_file'
4
+
5
+ module Usmu
6
+ # Class to represent files templated with a Tilt library. Most of the custom rendering logic is contained here.
7
+ class Layout < StaticFile
8
+ # @!attribute [r] type
9
+ # @return [String] the type of file this is. This is used to determine which template engine to use.
10
+ attr_reader :type
11
+
12
+ # @param configuration [Usmu::Configuration] The configuration for the website we're generating.
13
+ # @param name [String] The name of the file in the source directory.
14
+ # @param type [String] The type of template to use with the file. Used for testing purposes.
15
+ # @param content [String] The content of the file. Used for testing purposes.
16
+ # @param metadata [String] The metadata for the file. Used for testing purposes.
17
+ def initialize(configuration, name, type = nil, content = nil, metadata = nil)
18
+ super(configuration, name)
19
+
20
+ if type.nil?
21
+ type = name.split('.').last
22
+ unless ::Tilt.default_mapping[type]
23
+ raise "Templates of type '#{type}' aren't currently supported by Tilt. " +
24
+ 'Do you have the required gem installed?'
25
+ end
26
+ end
27
+ @type = type
28
+ path = File.join("#{content_path}", "#{name[0, name.length - type.length - 1]}")
29
+
30
+ if content.nil?
31
+ content = File.read("#{path}.#{type}")
32
+ end
33
+ @content = content
34
+
35
+ if metadata.nil?
36
+ meta_file = "#{path}.meta.yml"
37
+ metadata = if File.exist? meta_file
38
+ YAML.load_file(meta_file)
39
+ else
40
+ {}
41
+ end
42
+ end
43
+ @metadata = metadata
44
+
45
+ @parent = Layout.find_layout(configuration, metadata['layout'])
46
+ end
47
+
48
+ # @!attribute [r] metadata
49
+ # @return [Hash] the metadata associated with this layout.
50
+ #
51
+ # Returns the metadata associated with this layout.
52
+ #
53
+ # This will include any metadata from parent templates and default metadata
54
+ def metadata
55
+ if @parent.nil?
56
+ @metadata.deep_merge(@configuration['default meta'] || {})
57
+ else
58
+ @metadata.deep_merge(@parent.metadata)
59
+ end
60
+ end
61
+
62
+ # Renders the file with any templating language required and returns the result
63
+ #
64
+ # @param variables [Hash] Variables to be used in the template.
65
+ # @return [String] The rendered file.
66
+ def render(variables = {})
67
+ content = template_class.new("#{@name}.#{@type}", 1, @configuration[provider_name]) { @content }.
68
+ render(nil, get_variables(variables))
69
+ has_cr = content.index("\r")
70
+ content += (has_cr ? "\r\n" : "\n") if content[-1] != "\n"
71
+ if @parent.nil?
72
+ content
73
+ else
74
+ @parent.render({'content' => content})
75
+ end
76
+ end
77
+
78
+ # @!attribute [r] output_extension
79
+ # @return [String] the extension to use with the output file.
80
+ def output_extension
81
+ 'html'
82
+ end
83
+
84
+ # @!attribute [r] output_filename
85
+ # @return [String] the filename to use in the output directory.
86
+ #
87
+ # Returns the filename to use for the output directory with any modifications to the input filename required.
88
+ def output_filename
89
+ @name[0..@name.rindex('.')] + output_extension
90
+ end
91
+
92
+ # Static method to create a layout for a given configuration by it's name if it exists. This differs from
93
+ # `#initialise` in that it allows different types of values to be supplied as the name and will not fail if name
94
+ # is nil
95
+ #
96
+ # @param configuration [Usmu::Configuration] The configuration to use for the search
97
+ # @param name [String]
98
+ # If name is a string then search for a template with that name. Name here should not include
99
+ # file extension, eg. body not body.slim. If name is not a string then it will be returned verbatim. This means
100
+ # that name is nilable and can also be passed in as an Usmu::Layout already for testing purposes.
101
+ # @return [Usmu::Layout]
102
+ def self.find_layout(configuration, name)
103
+ if name.class.name == 'String'
104
+ Dir["#{configuration.layouts_path}/#{name}.*"].each do |f|
105
+ filename = File.basename(f)
106
+ if filename != "#{name}.meta.yml"
107
+ return new(configuration, f[(configuration.layouts_path.length + 1)..f.length])
108
+ end
109
+ end
110
+ else
111
+ name
112
+ end
113
+ end
114
+
115
+ # Tests if a given file is a valid Tilt template based on the filename.
116
+ #
117
+ # @param folder_type [String]
118
+ # One of `"source"` or `"layout"` depending on where the template is in the source tree.
119
+ # Not used by Usmu::Layout directly but intended to be available for future API.
120
+ # @param name [String] The filename to be tested.
121
+ # @return [Boolean]
122
+ def self.is_valid_file?(folder_type, name)
123
+ type = name.split('.').last
124
+ ::Tilt.default_mapping[type] ? true : false
125
+ end
126
+
127
+ protected
128
+
129
+ # @!attribute [r] template_class
130
+ # @return [Tilt::Template] the Tilt template engine for this layout
131
+ def template_class
132
+ @template_class ||= ::Tilt.default_mapping[@type]
133
+ end
134
+
135
+ # @!attribute [r] provider_name
136
+ # @return [String] the Tilt template engine's name for this layout
137
+ #
138
+ # Returns the Tilt template engine's name for this layout.
139
+ #
140
+ # This is used to determine which settings to use from the configuration file.
141
+ def provider_name
142
+ Tilt.default_mapping.lazy_map[@type].select {|x| x[0] == template_class.name }.first[1].split('/').last
143
+ end
144
+
145
+ # @!attribute [r] content_path
146
+ # @return [string] the base path to the files used by this class.
147
+ #
148
+ # Returns the base path to the files used by this class.
149
+ #
150
+ # This folder should be the parent folder for the file named by the name attribute.
151
+ #
152
+ # @see #name
153
+ def content_path
154
+ @configuration.layouts_path
155
+ end
156
+
157
+ private
158
+
159
+ # Utility function which collates variables to pass to the template engine.
160
+ #
161
+ # @return [Hash]
162
+ def get_variables(variables)
163
+ variables.deep_merge(metadata).deep_merge({site: @configuration})
164
+ end
165
+ end
166
+ end