usmu 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.rspec +1 -0
- data/.simplecov +4 -0
- data/.travis.yml +3 -0
- data/CONTRIBUTING.md +16 -0
- data/Guardfile +13 -0
- data/README.md +7 -6
- data/Rakefile +9 -10
- data/bin/usmu +5 -1
- data/lib/usmu.rb +73 -4
- data/lib/usmu/configuration.rb +40 -1
- data/lib/usmu/layout.rb +30 -7
- data/lib/usmu/page.rb +1 -0
- data/lib/usmu/plugin.rb +65 -0
- data/lib/usmu/plugin/core.rb +23 -0
- data/lib/usmu/site_generator.rb +17 -24
- data/lib/usmu/static_file.rb +10 -1
- data/lib/usmu/ui/console.rb +38 -10
- data/lib/usmu/version.rb +2 -2
- data/test/expected-site/default.html +14 -3
- data/test/site/layouts/html.meta.yml +1 -0
- data/test/{features/generator.feature → spec/acceptance/full_site_build.feature} +1 -0
- data/test/spec/acceptance/steps/full_site_build_steps.rb +24 -0
- data/test/spec/configuration_spec.rb +90 -1
- data/test/spec/layout_spec.rb +9 -17
- data/test/spec/mock/usmu/mock_plugin.rb +8 -0
- data/test/spec/page_spec.rb +9 -5
- data/test/spec/plugin/core_spec.rb +5 -0
- data/test/spec/plugin_spec.rb +49 -0
- data/test/spec/site_generator_spec.rb +0 -2
- data/test/spec/spec_helper.rb +12 -1
- data/test/spec/static_file_spec.rb +7 -1
- data/test/spec/support/shared_layout.rb +89 -5
- data/test/spec/ui/console_spec.rb +20 -0
- data/usmu-jruby.gemspec +6 -3
- data/usmu.gemspec +7 -6
- metadata +82 -27
- data/test/features/step_definitions/step_general.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9261434f327d1a56ce03785b20dd2ade1078901a
|
4
|
+
data.tar.gz: 3ad74fdce1d7f26fbe3dc3aebcffd95e4dbe78f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48ef1c5da18dbe2406f196f03154e846c7f85c552b39cb3190abd69fd5fcc5d83ca7d74ff0e7bdcef351135b6da097ca09729840250ec702c88c20bef3a3b923
|
7
|
+
data.tar.gz: 7ad1d0fe258d9d137b0a671b9f55580696d9dc75919f709f2b1ca551c19ad3f9f0293f65d2ae27abf02183f310742f1a8dcdad6f355aed6e394005f6ff762b80
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.simplecov
ADDED
data/.travis.yml
CHANGED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
## Bug reports
|
2
|
+
|
3
|
+
If you have a bug report, please include as much information as possible to help us diagnose the issue:
|
4
|
+
|
5
|
+
* A log of the console output if available
|
6
|
+
* A backtrace or log file (--trace and --log)
|
7
|
+
* If possible, a link to the source code for the website that is causing issues or a small example site that shows the
|
8
|
+
same issues.
|
9
|
+
|
10
|
+
## Contributing code to usmu
|
11
|
+
|
12
|
+
1. Fork it
|
13
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
14
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
15
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
16
|
+
5. Create a new Pull Request
|
data/Guardfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec, cmd: 'rspec', spec_paths: ['test/spec'] do
|
5
|
+
watch(%r{^test/spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/usmu/(.+)\.rb$}) { |m| "test/spec/#{m[1]}_spec.rb" }
|
7
|
+
watch(%r{^test/spec/support}) { 'test/spec' }
|
8
|
+
watch('test/spec/spec_helper.rb') { 'test/spec' }
|
9
|
+
|
10
|
+
# Turnip features and steps
|
11
|
+
#watch(%r{^spec/acceptance/(.+)\.feature$})
|
12
|
+
#watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
13
|
+
end
|
data/README.md
CHANGED
@@ -35,16 +35,17 @@ slim:
|
|
35
35
|
:pretty: true
|
36
36
|
```
|
37
37
|
|
38
|
-
|
38
|
+
### Ruby Compatibility
|
39
39
|
|
40
|
-
1.
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
Officially, we support MRI 1.9.3 and onwards, however we recommend the latest versions. [1.9.3 is no longer maintained][ruby-maint]
|
41
|
+
and is only supported here to help out the Rubinius and JRuby folks.
|
42
|
+
|
43
|
+
We only officially support MRI, however Travis does run against both Rubinius and JRuby to track compatibility and
|
44
|
+
there's a reasonable track record so far. Compatibility patches are very welcome.
|
45
45
|
|
46
46
|
[gh-contrib]: https://github.com/usmu/usmu/graphs/contributors
|
47
47
|
[gh-issues]: https://github.com/usmu/usmu/issues
|
48
48
|
[license]: https://github.com/usmu/usmu/blob/master/LICENSE.md
|
49
49
|
[tilt-support]: https://github.com/rtomayko/tilt/blob/master/README.md
|
50
50
|
[template-options]: https://github.com/rtomayko/tilt/blob/master/docs/TEMPLATES.md
|
51
|
+
[ruby-maint]: https://bugs.ruby-lang.org/projects/ruby/wiki/ReleaseEngineering
|
data/Rakefile
CHANGED
@@ -2,8 +2,6 @@ lib = File.expand_path('../lib', __FILE__)
|
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
-
require 'cucumber'
|
6
|
-
require 'cucumber/rake/task'
|
7
5
|
require 'usmu/version'
|
8
6
|
|
9
7
|
def current_gems
|
@@ -11,23 +9,24 @@ def current_gems
|
|
11
9
|
end
|
12
10
|
|
13
11
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
14
|
-
t.pattern = 'test/spec
|
15
|
-
end
|
16
|
-
|
17
|
-
Cucumber::Rake::Task.new(:features) do |t|
|
18
|
-
t.cucumber_opts = 'test/features'
|
12
|
+
t.pattern = 'test/spec'
|
19
13
|
end
|
20
14
|
|
21
15
|
desc 'Run all test scripts'
|
22
|
-
task :test => [:clean, :spec
|
16
|
+
task :test => [:clean, :spec]
|
23
17
|
|
24
18
|
desc 'Run CI test suite'
|
25
19
|
task :ci => [:test]
|
26
20
|
|
27
21
|
desc 'Clean up after tests'
|
28
22
|
task :clean do
|
29
|
-
|
30
|
-
|
23
|
+
[
|
24
|
+
'test/coverage',
|
25
|
+
'test/site/site',
|
26
|
+
current_gems,
|
27
|
+
].flatten.each do |f|
|
28
|
+
rm_r f if File.exist? f
|
29
|
+
end
|
31
30
|
end
|
32
31
|
|
33
32
|
namespace :gem do
|
data/bin/usmu
CHANGED
data/lib/usmu.rb
CHANGED
@@ -1,3 +1,74 @@
|
|
1
|
+
require 'logging'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
Logging.init :debug, :info, :success, :warn, :error, :fatal
|
5
|
+
Logging.color_scheme(
|
6
|
+
'console',
|
7
|
+
:lines => {
|
8
|
+
:success => :green,
|
9
|
+
:warn => :yellow,
|
10
|
+
:error => :red,
|
11
|
+
:fatal => :red,
|
12
|
+
},
|
13
|
+
)
|
14
|
+
|
15
|
+
# This module contains all the code for the Usmu site generator
|
16
|
+
module Usmu
|
17
|
+
@log = Logging.logger['Usmu']
|
18
|
+
@log.level = :all
|
19
|
+
@log.additive = false
|
20
|
+
@log.appenders = Logging.appenders.stdout(
|
21
|
+
'usmu-stdout',
|
22
|
+
:level => :info,
|
23
|
+
:layout => Logging.layouts.pattern(
|
24
|
+
:pattern => '%m\n',
|
25
|
+
:color_scheme => 'console',
|
26
|
+
),
|
27
|
+
)
|
28
|
+
|
29
|
+
# Enable logging of all events to the console
|
30
|
+
#
|
31
|
+
# @return [void]
|
32
|
+
def self.verbose_logging
|
33
|
+
Logging.appenders['usmu-stdout'].level = :all
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Disable all log messages other than errors. Warnings will be suppressed.
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
def self.quiet_logging
|
41
|
+
Logging.appenders['usmu-stdout'].level = :error
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Adds a file-based logger
|
46
|
+
#
|
47
|
+
# @param [String] filename Filename of the file to log to.
|
48
|
+
# @return [void]
|
49
|
+
def self.add_file_logger(filename)
|
50
|
+
@log.add_appenders(Logging.appenders.file(filename, :filename => filename, :level => :all))
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
# :nocov:
|
55
|
+
# This is primarily a testing helper
|
56
|
+
|
57
|
+
# Disables stdout logging across the application. This is used to hide stack traces but still log them to the file
|
58
|
+
# log if it is in use.
|
59
|
+
#
|
60
|
+
# @return [void]
|
61
|
+
def self.disable_stdout_logging
|
62
|
+
@log.remove_appenders('usmu-stdout')
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
# :nocov:
|
66
|
+
|
67
|
+
def self.plugins
|
68
|
+
@plugins ||= Usmu::Plugin.new
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
1
72
|
%W{
|
2
73
|
usmu/version
|
3
74
|
usmu/configuration
|
@@ -5,8 +76,6 @@
|
|
5
76
|
usmu/layout
|
6
77
|
usmu/page
|
7
78
|
usmu/site_generator
|
79
|
+
usmu/plugin
|
80
|
+
usmu/plugin/core
|
8
81
|
}.each { |f| require f }
|
9
|
-
|
10
|
-
# This module contains all the code for the Usmu site generator
|
11
|
-
module Usmu
|
12
|
-
end
|
data/lib/usmu/configuration.rb
CHANGED
@@ -4,10 +4,12 @@ module Usmu
|
|
4
4
|
# This class is used to represent a configuration file. This file should be a YAML file and called `usmu.yml`
|
5
5
|
# by default.
|
6
6
|
class Configuration
|
7
|
+
@log = Logging.logger[self]
|
8
|
+
|
7
9
|
# @!attribute [r] config_file
|
8
10
|
# @return [String] the name of the file used to load the configuration.
|
9
11
|
attr_reader :config_file
|
10
|
-
# @!attribute [r]
|
12
|
+
# @!attribute [r] config_dir
|
11
13
|
# @return [String] the folder that the configuration was loaded from.
|
12
14
|
attr_reader :config_dir
|
13
15
|
|
@@ -15,6 +17,7 @@ module Usmu
|
|
15
17
|
#
|
16
18
|
# @return [Usmu::Configuration]
|
17
19
|
def self.from_file(filename)
|
20
|
+
@log.debug("Loading configuration from #{filename}")
|
18
21
|
from_hash(YAML.load_file(filename), filename)
|
19
22
|
end
|
20
23
|
|
@@ -31,6 +34,12 @@ module Usmu
|
|
31
34
|
get_path @config['source'] || 'src'
|
32
35
|
end
|
33
36
|
|
37
|
+
# @!attribute [r] source_files
|
38
|
+
# @return [Array<String>] a list of renderable files in the source folder
|
39
|
+
def source_files
|
40
|
+
get_files source_path
|
41
|
+
end
|
42
|
+
|
34
43
|
# @!attribute [r] destination_path
|
35
44
|
# @return [String] the full path to the destination folder
|
36
45
|
def destination_path
|
@@ -43,6 +52,12 @@ module Usmu
|
|
43
52
|
get_path @config['layouts'] || 'layouts'
|
44
53
|
end
|
45
54
|
|
55
|
+
# @!attribute [r] layouts_files
|
56
|
+
# @return [Array<String>] a list of renderable files in the layouts folder
|
57
|
+
def layouts_files
|
58
|
+
get_files layouts_path
|
59
|
+
end
|
60
|
+
|
46
61
|
# An index accessor to directly access the configuration file. It should be noted that `['source']` and
|
47
62
|
# `#source_path` and other similar pairs will have different values. `['source']` is the raw value from the
|
48
63
|
# configuration file while the latter is a path on the system, potentially altered by the path from the current
|
@@ -63,6 +78,7 @@ module Usmu
|
|
63
78
|
# @see Usmu::Configuration.from_file
|
64
79
|
# @see Usmu::Configuration.from_hash
|
65
80
|
def initialize(hash, config_path)
|
81
|
+
@log = Logging.logger[self]
|
66
82
|
@config = hash
|
67
83
|
@config_file = config_path
|
68
84
|
@config_dir = config_path ? File.dirname(config_path) : nil
|
@@ -79,5 +95,28 @@ module Usmu
|
|
79
95
|
File.join(@config_dir, path)
|
80
96
|
end
|
81
97
|
end
|
98
|
+
|
99
|
+
# Helper to determine if a filename is excluded according to the exclude configuration parameter.
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
def excluded?(filename)
|
103
|
+
flags = defined?(File::FNM_EXTGLOB) ? File::FNM_EXTGLOB | File::FNM_PATHNAME : File::FNM_PATHNAME
|
104
|
+
(@config['exclude'] || []).each do |f|
|
105
|
+
f += '**/*' if f[-1] == '/'
|
106
|
+
return true if File.fnmatch(f, filename, flags)
|
107
|
+
end
|
108
|
+
false
|
109
|
+
end
|
110
|
+
|
111
|
+
# Helper function to search a directory recursively and return a list of files that are renderable.
|
112
|
+
#
|
113
|
+
# @param [String] directory the directory to search
|
114
|
+
# @param [Boolean] layout is this directory a layouts_path
|
115
|
+
# @return [Array<Usmu::Layout>, Array<Usmu::StaticFile>] Either an array of Layouts or StaticFiles in the directory
|
116
|
+
def get_files(directory)
|
117
|
+
Dir["#{directory}/**/*"].select {|f| !f.match(/\.meta.yml$/) }.map do |f|
|
118
|
+
f[(directory.length + 1)..f.length]
|
119
|
+
end.select {|f| not excluded? f}
|
120
|
+
end
|
82
121
|
end
|
83
122
|
end
|
data/lib/usmu/layout.rb
CHANGED
@@ -42,7 +42,8 @@ module Usmu
|
|
42
42
|
end
|
43
43
|
@metadata = metadata
|
44
44
|
|
45
|
-
@parent =
|
45
|
+
@parent = nil
|
46
|
+
@parent = Layout.find_layout(configuration, self.metadata['layout'])
|
46
47
|
end
|
47
48
|
|
48
49
|
# @!attribute [r] metadata
|
@@ -53,9 +54,9 @@ module Usmu
|
|
53
54
|
# This will include any metadata from parent templates and default metadata
|
54
55
|
def metadata
|
55
56
|
if @parent.nil?
|
56
|
-
|
57
|
+
(@configuration['default meta'] || {}).dup.deep_merge!(@metadata)
|
57
58
|
else
|
58
|
-
@metadata.deep_merge(@
|
59
|
+
@parent.metadata.deep_merge!(@metadata)
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -75,10 +76,25 @@ module Usmu
|
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
79
|
+
# @!attribute [r] input_path
|
80
|
+
# @return [String] the full path to the file in the source directory
|
81
|
+
def input_path
|
82
|
+
File.join(content_path, @name)
|
83
|
+
end
|
84
|
+
|
78
85
|
# @!attribute [r] output_extension
|
79
86
|
# @return [String] the extension to use with the output file.
|
80
87
|
def output_extension
|
81
|
-
|
88
|
+
case @type
|
89
|
+
when 'erb', 'rhtml', 'erubis', 'liquid'
|
90
|
+
nil
|
91
|
+
when 'coffee'
|
92
|
+
'js'
|
93
|
+
when 'less', 'sass', 'scss'
|
94
|
+
'css'
|
95
|
+
else
|
96
|
+
'html'
|
97
|
+
end
|
82
98
|
end
|
83
99
|
|
84
100
|
# @!attribute [r] output_filename
|
@@ -86,7 +102,11 @@ module Usmu
|
|
86
102
|
#
|
87
103
|
# Returns the filename to use for the output directory with any modifications to the input filename required.
|
88
104
|
def output_filename
|
89
|
-
|
105
|
+
if output_extension
|
106
|
+
@name[0..@name.rindex('.')] + output_extension
|
107
|
+
else
|
108
|
+
@name[0..@name.rindex('.') - 1]
|
109
|
+
end
|
90
110
|
end
|
91
111
|
|
92
112
|
# Static method to create a layout for a given configuration by it's name if it exists. This differs from
|
@@ -100,13 +120,16 @@ module Usmu
|
|
100
120
|
# that name is nilable and can also be passed in as an Usmu::Layout already for testing purposes.
|
101
121
|
# @return [Usmu::Layout]
|
102
122
|
def self.find_layout(configuration, name)
|
103
|
-
if name
|
123
|
+
if name === 'none'
|
124
|
+
nil
|
125
|
+
elsif name.class.name == 'String'
|
104
126
|
Dir["#{configuration.layouts_path}/#{name}.*"].each do |f|
|
105
127
|
filename = File.basename(f)
|
106
128
|
if filename != "#{name}.meta.yml"
|
107
129
|
return new(configuration, f[(configuration.layouts_path.length + 1)..f.length])
|
108
130
|
end
|
109
131
|
end
|
132
|
+
nil
|
110
133
|
else
|
111
134
|
name
|
112
135
|
end
|
@@ -160,7 +183,7 @@ module Usmu
|
|
160
183
|
#
|
161
184
|
# @return [Hash]
|
162
185
|
def get_variables(variables)
|
163
|
-
|
186
|
+
{site: @configuration}.deep_merge!(metadata).deep_merge!(variables)
|
164
187
|
end
|
165
188
|
end
|
166
189
|
end
|
data/lib/usmu/page.rb
CHANGED
data/lib/usmu/plugin.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
module Usmu
|
3
|
+
class Plugin
|
4
|
+
def initialize
|
5
|
+
@log = Logging.logger['Usmu::Plugin']
|
6
|
+
end
|
7
|
+
|
8
|
+
# Loads all plugins that are available as gems. This is determined by looking at the gem's name. Anything prefixed
|
9
|
+
# with the string 'usmu-' will be recognised as a plugin. This will load the gem according to the RubyGems
|
10
|
+
# recommendations for naming schemes. A gem named `usmu-s3_uploader` will be loaded by requiring the path
|
11
|
+
# `'usmu/s3_uploader'` and then then the class `Usmu::S3Uploader` will be instantiated as the plugins interface.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
def load_plugins
|
15
|
+
loaded = []
|
16
|
+
@log.debug('Loading plugins')
|
17
|
+
@log.debug('Loaded Usmu::Plugin::Core')
|
18
|
+
plugins.push Usmu::Plugin::Core.new
|
19
|
+
Gem::Specification.find_all { |s| s.name =~ /^usmu-/ }.each do |spec|
|
20
|
+
load_path = spec.name.gsub('-', '/')
|
21
|
+
require load_path
|
22
|
+
|
23
|
+
unless loaded.include? load_path
|
24
|
+
loaded << load_path
|
25
|
+
klass = load_path.split('/').map {|s| s.split('_').map(&:capitalize).join }.join('::')
|
26
|
+
@log.debug("Loading plugin #{klass} from '#{load_path}'")
|
27
|
+
plugins.push plugin_get(klass)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@log.debug("Loaded: #{plugins.inspect}")
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!attribute [r] plugins
|
34
|
+
# @return [Array] a list of all plugins discovered and loaded.
|
35
|
+
def plugins
|
36
|
+
@plugins ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
# Call all plugins and collate any data returned. nil can be returned explicitly to say this plugin has nothing to
|
40
|
+
# return.
|
41
|
+
# @param [Symbol] method The name of the method to call. This should be namespaced somehow. For example, a plugin
|
42
|
+
# called `usmu-s3` could use the method namespace `s3` and have a hook called `:s3_upload`
|
43
|
+
# @param [Array] args The arguments to pass through to plugins. Can be empty.
|
44
|
+
def invoke(method, *args)
|
45
|
+
@log.debug("Invoking plugin API #{method}")
|
46
|
+
plugins.map do |p|
|
47
|
+
if p.respond_to? method
|
48
|
+
@log.debug("Sending message to #{p.class.name}")
|
49
|
+
p.public_send method, *args
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end.select {|i| i}
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def plugin_get(klass)
|
59
|
+
object.const_get(klass).new
|
60
|
+
rescue NameError
|
61
|
+
# Ruby 1.9.3, dowp
|
62
|
+
klass.split('::').reduce(Object) {|memo, o| memo.const_get o }.new
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|