munge 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90a523f13c830272c0fb00314bff78658c2967c4
4
- data.tar.gz: c7875ddc140b85157f5e248920d1d1a951f3a1d4
3
+ metadata.gz: e8fc56a43cc01c94bce65df0af73e6d2028ac93f
4
+ data.tar.gz: 136d8b5a37e8fbc6ecb9fd69ae951eebe0a10b32
5
5
  SHA512:
6
- metadata.gz: 67093ea7b88f0a9fcf36970a1e29d268008d0958010c6fd9716183ec0480ab8e098a0426e8a7c5b0229293b29f768e03c791417bf27bb29e861a34cb62783d89
7
- data.tar.gz: 138f51ff91d5cb37c9d805b0bc622654e4b66f06f4b54d3edc046e2a841298a7f65f2e41f62202a5e43be8c405dfb83e6dcd112bc408c3441d48e95109442ded
6
+ metadata.gz: 1c4d0b4818104f8f08aa1a7fc196ab2d710b8259a04e7b98bede587f56487f06d533915621c1920e93338d6974432dac46432d26320fd5dd1284b4028ed51d13
7
+ data.tar.gz: cf7c2270b12795bdf4623596bc026967b55b8fb0c6e052c20c983d55d291ed0f8dfbf92c31813857b28672969b459a063a92a76314f920eaa90e08bd23506f2c
data/.rubocop.yml CHANGED
@@ -3,6 +3,15 @@ AllCops:
3
3
  - vendor/bundle/**/*
4
4
  - Gemfile
5
5
  - Rakefile
6
+ - seeds/**/*
7
+
8
+ Metrics/AbcSize:
9
+ Exclude:
10
+ - test/**/*
11
+
12
+ Metrics/MethodLength:
13
+ Exclude:
14
+ - test/**/*
6
15
 
7
16
  Style/AlignParameters:
8
17
  Enabled: false
data/.travis.yml CHANGED
@@ -1,4 +1,17 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.2
3
+ - 2.2
4
+ - 2.1
5
+ - ruby-head
6
+ cache: bundler
4
7
  before_install: gem install bundler -v 1.10.5
8
+ script: ./script/test
9
+ addons:
10
+ code_climate:
11
+ repo_token: b8fc4a1660d2067059476e3e579080fb6820daedbdb5e56cd9028f5dcc058fc8
12
+ notifications:
13
+ email: false
14
+ matrix:
15
+ fast_finish: true
16
+ allow_failures:
17
+ - rvm: ruby-head
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Munge
2
2
 
3
+ [![Build Status](https://travis-ci.org/zachahn/munge.svg?branch=master)](https://travis-ci.org/zachahn/munge)
4
+ [![Code Climate](https://codeclimate.com/github/zachahn/munge/badges/gpa.svg)](https://codeclimate.com/github/zachahn/munge)
5
+ [![Test Coverage](https://codeclimate.com/github/zachahn/munge/badges/coverage.svg)](https://codeclimate.com/github/zachahn/munge/coverage)
6
+
3
7
  Munge is a static site generator aiming to simplify complex build rules.
4
8
 
5
9
  SemVer will be followed once 1.0.0 is released.
@@ -7,67 +11,64 @@ Until then,
7
11
  the API should be considered experimental.
8
12
 
9
13
 
10
- ## Usage
11
-
12
- **Directory structure**
13
-
14
- ```
15
- dest/
16
- src/
17
- layouts/
18
- layout.html
19
- index.html
20
- application.rb
21
- config.yml
22
- Gemfile
23
- ```
14
+ ## Installation
24
15
 
25
- **`application.rb`**
16
+ Add this line to your application's Gemfile:
26
17
 
27
18
  ```ruby
28
- require "munge"
19
+ gem 'munge'
20
+ ```
29
21
 
30
- app = Munge::Application.new("./config.yml")
22
+ And then execute:
31
23
 
32
- app.source
33
- .reject { |item| item.path.relative =~ %r(^layouts/) }
34
- .each { |item| item.route = item.path.dirname }
35
- .map { |item| item.path.dirname }
24
+ $ bundle
36
25
 
37
- app.write
38
- ```
26
+ Or install it yourself as:
39
27
 
40
- **`config.yml`**
41
-
42
- ```yaml
43
- ---
44
- source: src
45
- dest: dest
46
- binary_extensions:
47
- - jpg
48
- - jpeg
49
- - png
50
- - gif
51
- - ico
52
- index: index.html
53
- ```
28
+ $ gem install munge
54
29
 
55
30
 
56
- ## Installation
31
+ ## Usage
57
32
 
58
- Add this line to your application's Gemfile:
33
+ After installing your gem, you can start a project using the command line client.
59
34
 
60
- ```ruby
61
- gem 'munge'
35
+ ```
36
+ munge init path/to/project
62
37
  ```
63
38
 
64
- And then execute:
39
+ The three main files of your application are `config.yml`, `data.yml`, and `rules.rb`.
65
40
 
66
- $ bundle
41
+ Here's an example `rules.rb` for a blog.
67
42
 
68
- Or install it yourself as:
43
+ ```ruby
44
+ # home page
45
+ app.source
46
+ .select { |item| item.id == "home" } # looks for items where path is "src/home.*"
47
+ .each { |item| item.route = "" } # sets output file to "/index.html"
48
+ .each { |item| item.layout = "default"} # sets layout to "layouts/default.*"
49
+ .each { |item| item[:title] = "home" } # sets additional frontmatter variables
50
+ .each { |item| item.transform(:tilt) } # have Tilt compile this file
69
51
 
70
- $ gem install munge
52
+ # blog posts
53
+ app.source
54
+ .select { |item| item.relpath =~ %r(^posts/) } # looks for items in "src/posts/**/*"
55
+ .each { |item| item.route = "blog/#{item.basename}" } # sets output file to "/blog/#{basename}/index.html"
56
+ .each { |item| item.layout = "post" }
57
+ .each { |item| item.transform } # sets transform to Tilt (default)
58
+
59
+ # blog index
60
+ posts_for_index =
61
+ app.source
62
+ .find_all { |item| item.route =~ %r(^blog/) }
63
+ .sort_by { |item| item.route }
64
+ .reverse
65
+
66
+ app.create("blog/index.html.erb", "", posts: posts_for_index) do |item|
67
+ item.route = "blog" # sets output file to "/blog/index.html"
68
+ item.layout = "list"
69
+ item.transform
70
+ end
71
+ ```
71
72
 
72
73
 
73
74
  ## Contributing
data/exe/munge ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "munge"
3
+ require "munge/cli"
4
+
5
+ Munge::CLI.start(ARGV)
@@ -1,33 +1,52 @@
1
1
  module Munge
2
2
  class Application
3
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
3
4
  def initialize(config_path)
4
- @config = YAML.load_file(File.expand_path(config_path))
5
- @root = File.dirname(File.expand_path(config_path))
5
+ config = YAML.load_file(File.expand_path(config_path))
6
6
 
7
- @source_dir = File.expand_path(@config["source"], @root)
8
- @dest_dir = File.expand_path(@config["dest"], @root)
7
+ root_path = File.dirname(File.expand_path(config_path))
8
+ source_path = File.expand_path(config["source"], root_path)
9
+ layouts_path = File.expand_path(config["layouts"], root_path)
10
+ output_path = File.expand_path(config["output"], root_path)
11
+ data_path = File.expand_path(config["data"], root_path)
9
12
 
10
- @source = Source.new(@source_dir)
13
+ global_data = YAML.load_file(data_path) || {}
14
+
15
+ @source = Core::Source.new(source_path, config["binary_extensions"])
16
+ @transform = Core::Transform.new(
17
+ source_path,
18
+ layouts_path,
19
+ global_data,
20
+ @source
21
+ )
22
+ @writer = Core::Write.new(output_path, config["index"])
11
23
  end
24
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
12
25
 
13
26
  attr_reader :source
14
27
 
15
- def write
28
+ def write(&block)
16
29
  @source
17
30
  .reject { |item| item.route.nil? }
18
- .map { |item| [item, resolve_write_path(item)] }
19
- .each { |_, dest_path| FileUtils.mkdir_p(File.dirname(dest_path)) }
20
- .map { |item, dest_path| [item.rendered_output, dest_path] }
21
- .each { |content, dest_path| File.write(dest_path, content) }
31
+ .each { |item| render_and_write(item, &block) }
32
+ end
33
+
34
+ def new_virtual_item(*args)
35
+ Munge::Item::Virtual.new(*args)
36
+ end
37
+
38
+ def create(*args, &block)
39
+ item = new_virtual_item(*args)
40
+ yield item if block_given?
41
+ @source.push(item)
22
42
  end
23
43
 
24
44
  private
25
45
 
26
- def resolve_write_path(item)
27
- if item.route[-1] == "/"
28
- File.join(@dest_dir, item.route, @config["index"])
29
- else
30
- File.join(@dest_dir, item.route)
46
+ def render_and_write(item, &block)
47
+ did_write = @writer.write(item.route, @transform.call(item))
48
+ if block_given?
49
+ block.call(item, did_write)
31
50
  end
32
51
  end
33
52
  end
@@ -43,8 +43,15 @@ module Munge
43
43
  end
44
44
  end
45
45
 
46
- def initialize(string)
46
+ def initialize(string, frontmatter = nil)
47
47
  @frontmatter, @content = self.class.parse(string)
48
+
49
+ if frontmatter
50
+ @frontmatter = @frontmatter.merge(frontmatter)
51
+ end
52
+ rescue ArgumentError
53
+ @frontmatter = frontmatter || {}
54
+ @content = string
48
55
  end
49
56
 
50
57
  attr_accessor :frontmatter, :content
@@ -2,11 +2,11 @@ module Munge
2
2
  module Attribute
3
3
  class Path
4
4
  def initialize(source_path, file_path)
5
- @relative = resolve_relative(source_path, file_path).freeze
6
- @absolute = file_path.dup.freeze
7
- @basename = resolve_basename(file_path).freeze
8
- @extnames = resolve_extnames(file_path).freeze
9
- @dirname = resolve_dirname(@relative).freeze
5
+ @relative = resolve_relative(source_path, file_path)
6
+ @absolute = file_path
7
+ @basename = resolve_basename(file_path)
8
+ @extnames = resolve_extnames(file_path)
9
+ @dirname = resolve_dirname(@relative)
10
10
  end
11
11
 
12
12
  attr_reader :relative, :absolute, :basename, :extnames, :dirname
data/lib/munge/cli.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "thor"
2
+
3
+ module Munge
4
+ class CLI < Thor
5
+ include Thor::Actions
6
+
7
+ def self.source_root
8
+ File.expand_path("../../../seeds", __FILE__)
9
+ end
10
+
11
+ desc "init PATH", "Create new site at PATH"
12
+ def init(path)
13
+ directory ".", path
14
+ end
15
+
16
+ desc "build", "Build in current directory"
17
+ def build
18
+ config_path = File.join(destination_root, "config.yml")
19
+ rules_path = File.join(destination_root, "rules.rb")
20
+
21
+ Munge::Runner.write(config_path, rules_path)
22
+ end
23
+
24
+ desc "version", "Print version"
25
+ def version
26
+ puts "munge #{Munge::VERSION}"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ module Munge
2
+ class ItemFactory
3
+ def initialize(sourcepath, binary_extensions)
4
+ @sourcepath = sourcepath
5
+ @binary_extensions = binary_extensions
6
+ end
7
+
8
+ def create(filepath)
9
+ path = Munge::Attribute::Path.new(@sourcepath, filepath)
10
+ content = Munge::Attribute::Content.new(File.read(path.absolute))
11
+ stat = Munge::Attribute::Metadata.new(filepath)
12
+
13
+ if binary_extension?(filepath)
14
+ Munge::Item::Binary.new(path, content, stat)
15
+ else
16
+ Munge::Item::Text.new(path, content, stat)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def binary_extension?(filepath)
23
+ file_extensions = File.basename(filepath).split(".")[1..-1]
24
+
25
+ extensions_intersection = @binary_extensions & file_extensions
26
+
27
+ !extensions_intersection.empty?
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "source/item_factory"
2
+
3
+ module Munge
4
+ module Core
5
+ class Source
6
+ include Enumerable
7
+
8
+ def initialize(source_abspath, binary_extensions = [])
9
+ item_factory = ItemFactory.new(source_abspath, binary_extensions)
10
+ pattern = File.join(source_abspath, "**", "*")
11
+
12
+ @items =
13
+ Dir.glob(pattern)
14
+ .reject { |item_path| File.directory?(item_path) }
15
+ .map { |item_path| item_factory.create(item_path) }
16
+ .map { |item| [item.id, item] }
17
+ .to_h
18
+ end
19
+
20
+ def each
21
+ return enum_for(:each) unless block_given?
22
+
23
+ @items.each_value do |item|
24
+ yield item
25
+ end
26
+ end
27
+
28
+ def push(virtual_item)
29
+ key = virtual_item.id
30
+ @items[key] = virtual_item
31
+ end
32
+
33
+ def [](id)
34
+ @items[id]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,51 @@
1
+ module Munge
2
+ module Core
3
+ class Transform
4
+ def initialize(source_path,
5
+ layouts_path,
6
+ global_data,
7
+ source)
8
+ @scope_factory = Core::TransformScopeFactory.new(
9
+ source_path,
10
+ layouts_path,
11
+ global_data,
12
+ source,
13
+ Munge::Helper
14
+ )
15
+ end
16
+
17
+ def call(item)
18
+ item.transforms
19
+ .map { |name, args| [resolve_transformer(name), args] }
20
+ .inject(item.content) do |content, params|
21
+ transformer, args = params
22
+
23
+ t = transformer.new(@scope_factory)
24
+
25
+ t.call(item, content, *args)
26
+ end
27
+ end
28
+
29
+ def resolve_transformer(identifier)
30
+ resolver = proc do |name|
31
+ if Munge::Transformer.constants.include?(name)
32
+ return Munge::Transformer.const_get(name)
33
+ end
34
+ end
35
+
36
+ resolver.call(identifier.to_sym)
37
+
38
+ resolver.call(underscore_to_camel(identifier.to_s).to_sym)
39
+ end
40
+
41
+ private
42
+
43
+ def underscore_to_camel(string)
44
+ string
45
+ .split("_")
46
+ .map(&:capitalize)
47
+ .join("")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,42 @@
1
+ module Munge
2
+ module Core
3
+ class TransformScopeFactory
4
+ def initialize(source_path,
5
+ layouts_path,
6
+ global_data,
7
+ source,
8
+ helper_container)
9
+ @source_path = source_path
10
+ @layouts_path = layouts_path
11
+ @global_data = global_data
12
+ @source = source
13
+ @helper_container = helper_container
14
+ end
15
+
16
+ def create(load_helpers = true)
17
+ scope = Munge::Transformer::Tilt::Scope.new(
18
+ @source_path,
19
+ @layouts_path,
20
+ @global_data,
21
+ @source
22
+ )
23
+
24
+ if load_helpers
25
+ extend_with_helpers(scope)
26
+ end
27
+
28
+ scope
29
+ end
30
+
31
+ private
32
+
33
+ def extend_with_helpers(scope)
34
+ Munge::Helper.constants
35
+ .map { |sym| @helper_container.const_get(sym) }
36
+ .each { |helper| scope.extend(helper) }
37
+
38
+ scope
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ module Munge
2
+ module Core
3
+ class Write
4
+ def initialize(output, index)
5
+ @output = output
6
+ @index = index
7
+ end
8
+
9
+ def write(route, content)
10
+ relpath = resolve_filepath(route)
11
+ abspath = File.join(@output, relpath)
12
+
13
+ FileUtils.mkdir_p(File.dirname(abspath))
14
+
15
+ if File.exist?(abspath) && File.read(abspath) == content
16
+ return false
17
+ else
18
+ File.write(abspath, content)
19
+ true
20
+ end
21
+ end
22
+
23
+ def resolve_filepath(preferred_filename)
24
+ basename = File.basename(preferred_filename)
25
+
26
+ if basename.include?(".")
27
+ preferred_filename
28
+ else
29
+ "#{preferred_filename}/#{@index}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module Munge
2
+ module Helper
3
+ module Find
4
+ def items
5
+ @source
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,117 @@
1
+ module Munge
2
+ module Helper
3
+ module Rendering
4
+ def render(item, manual_engine = nil, **additional_data, &content_block)
5
+ content = resolve_render_content(item, &content_block)
6
+ renderers = resolve_render_renderer(item, manual_engine)
7
+ data = merged_data(item.frontmatter, additional_data)
8
+
9
+ renderers
10
+ .inject(content) do |output, engine|
11
+ template = engine.new { output }
12
+ template.render(self, data)
13
+ end
14
+ end
15
+
16
+ def layout(path, **additional_data, &block)
17
+ actual_layout = find_layout(path)
18
+
19
+ if block_given?
20
+ if block.binding.local_variable_defined?(:_erbout)
21
+ layout_within_template(actual_layout, additional_data, &block)
22
+ else
23
+ layout_outside_template(actual_layout, additional_data, &block)
24
+ end
25
+ else
26
+ layout_without_block(actual_layout, additional_data)
27
+ end
28
+ end
29
+
30
+ def render_with_layout(item, manual_engine = nil, **additional_data, &content_block)
31
+ data =
32
+ merged_data(item.frontmatter, additional_data)
33
+
34
+ inner =
35
+ if block_given?
36
+ render(item, manual_engine, **data, &content_block)
37
+ else
38
+ render(item, manual_engine, **data)
39
+ end
40
+
41
+ if item.layout.nil?
42
+ inner
43
+ else
44
+ layout(item.layout, data) do
45
+ inner
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def merged_data(*data)
53
+ hash_with_string_and_symbol_keys =
54
+ data.inject(@global_data) do |merged, datum|
55
+ merged.merge(datum)
56
+ end
57
+
58
+ hash_with_string_and_symbol_keys
59
+ .each_with_object({}) do |(key, value), memo|
60
+ memo[key.to_sym] = value
61
+ end
62
+ end
63
+
64
+ def find_layout(path)
65
+ pattern = File.join(@layouts_path, path)
66
+ Dir["#{pattern}*"].first
67
+ end
68
+
69
+ def layout_within_template(actual_layout, additional_data, &block)
70
+ original_erbout = block.binding.local_variable_get(:_erbout)
71
+
72
+ block.binding.local_variable_set(:_erbout, "")
73
+
74
+ inside = block.call
75
+
76
+ template = ::Tilt.new(actual_layout)
77
+ result = template.render(self, merged_data(additional_data)) do
78
+ inside
79
+ end
80
+
81
+ final = original_erbout + result
82
+
83
+ block.binding.local_variable_set(:_erbout, final)
84
+
85
+ ""
86
+ end
87
+
88
+ def layout_outside_template(actual_layout, additional_data, &block)
89
+ template = ::Tilt.new(actual_layout)
90
+ template.render(self, merged_data(additional_data)) do
91
+ block.call
92
+ end
93
+ end
94
+
95
+ def layout_without_block(actual_layout, additional_data)
96
+ template = ::Tilt.new(actual_layout)
97
+ template.render(self, merged_data(additional_data))
98
+ end
99
+
100
+ def resolve_render_content(item, &content_block)
101
+ if block_given?
102
+ content_block.call
103
+ else
104
+ item.content
105
+ end
106
+ end
107
+
108
+ def resolve_render_renderer(item, manual_engine)
109
+ if manual_engine.nil?
110
+ ::Tilt.templates_for(item.relpath)
111
+ else
112
+ [::Tilt[manual_engine]].compact
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,4 @@
1
+ module Munge
2
+ module Helper
3
+ end
4
+ end
@@ -0,0 +1,85 @@
1
+ module Munge
2
+ module Item
3
+ class Base
4
+ def initialize(path = nil, content = nil, info = nil)
5
+ @path = path
6
+ @content = content
7
+ @info = info
8
+ @layout = nil
9
+ @route = nil
10
+ @transforms = []
11
+ end
12
+
13
+ attr_reader :transforms
14
+ attr_accessor :route, :layout
15
+
16
+ def id
17
+ if dirname == ""
18
+ basename
19
+ else
20
+ "#{dirname}/#{basename}"
21
+ end
22
+ end
23
+
24
+ def relpath
25
+ @path.relative
26
+ end
27
+
28
+ def dirname
29
+ if File.dirname(relpath) == "."
30
+ ""
31
+ else
32
+ File.dirname(relpath)
33
+ end
34
+ end
35
+
36
+ def filename
37
+ File.basename(relpath)
38
+ end
39
+
40
+ def basename
41
+ filename.split(".").first
42
+ end
43
+
44
+ def content
45
+ @content.content
46
+ end
47
+
48
+ def frontmatter
49
+ @content.frontmatter
50
+ end
51
+
52
+ def stat
53
+ @info.stat
54
+ end
55
+
56
+ def virtual?
57
+ false
58
+ end
59
+
60
+ def binary?
61
+ false
62
+ end
63
+
64
+ def text?
65
+ false
66
+ end
67
+
68
+ def transform(transformer = :tilt, *args)
69
+ @transforms.push([transformer, args])
70
+ end
71
+
72
+ def [](key)
73
+ frontmatter[key]
74
+ end
75
+
76
+ def []=(key, value)
77
+ frontmatter[key] = value
78
+ end
79
+
80
+ def to_s
81
+ "#{super} #{relpath} #{route}"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,9 @@
1
+ module Munge
2
+ module Item
3
+ class Binary < Base
4
+ def binary?
5
+ true
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Munge
2
+ module Item
3
+ class Text < Base
4
+ def text?
5
+ true
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module Munge
2
+ module Item
3
+ class Virtual < Base
4
+ def initialize(relpath, kontent, frontmatter = nil)
5
+ content =
6
+ if kontent.is_a?(String)
7
+ Munge::Attribute::Content.new(kontent, frontmatter)
8
+ else
9
+ kontent
10
+ end
11
+
12
+ super(relpath, content)
13
+ end
14
+
15
+ def relpath
16
+ @path
17
+ end
18
+
19
+ def virtual?
20
+ true
21
+ end
22
+
23
+ def text?
24
+ true
25
+ end
26
+
27
+ def content=(new_content)
28
+ @content.content = new_content
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module Munge
2
+ class Runner
3
+ class << self
4
+ def method_missing(method, config_path, rules_path, *args)
5
+ runner = new(config_path, rules_path)
6
+ runner.public_send(method, *args)
7
+ end
8
+
9
+ def respond_to_missing?(method, *)
10
+ if instance_methods.include?(method)
11
+ true
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize(config_path, rules_path)
19
+ @app = app = Munge::Application.new(config_path)
20
+
21
+ binding.eval(File.read(rules_path), rules_path)
22
+ end
23
+
24
+ def write
25
+ @app.write do |item, did_write|
26
+ if did_write
27
+ puts "wrote #{item.route}"
28
+ else
29
+ puts "identical #{item.route}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ module Munge
2
+ module Transformer
3
+ class ImageOptim
4
+ def initialize(_scope_factory)
5
+ end
6
+
7
+ def call(item, content = nil, **initialization)
8
+ actual_content =
9
+ if content.nil?
10
+ item.content
11
+ else
12
+ content
13
+ end
14
+
15
+ optimizer = ::ImageOptim.new(**initialization)
16
+ optimizer.optimize_image_data(actual_content)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Munge
2
+ module Transformer
3
+ class Tilt
4
+ class Scope
5
+ include Munge::Helper::Rendering
6
+
7
+ def initialize(source_path,
8
+ layouts_path,
9
+ global_data,
10
+ source)
11
+ @source_path = source_path
12
+ @layouts_path = layouts_path
13
+ @global_data = global_data
14
+ @source = source
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "tilt/scope"
2
+
3
+ module Munge
4
+ module Transformer
5
+ class Tilt
6
+ def initialize(scope_factory)
7
+ @scope = scope_factory.create
8
+ end
9
+
10
+ def call(item, content = nil, renderer = nil)
11
+ if content.nil?
12
+ @scope.render_with_layout(item, renderer)
13
+ else
14
+ @scope.render_with_layout(item, renderer) do
15
+ content
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/munge/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Munge
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/munge.rb CHANGED
@@ -5,12 +5,23 @@ require "yaml"
5
5
  require "tilt"
6
6
 
7
7
  require "munge/version"
8
- require "munge/source"
9
8
  require "munge/attribute/content"
10
9
  require "munge/attribute/metadata"
11
10
  require "munge/attribute/path"
12
- require "munge/item"
11
+ require "munge/item/base"
12
+ require "munge/item/binary"
13
+ require "munge/item/text"
14
+ require "munge/item/virtual"
15
+ require "munge/helper"
16
+ require "munge/helper/find"
17
+ require "munge/helper/rendering"
18
+ require "munge/transformer/tilt"
19
+ require "munge/core/source"
20
+ require "munge/core/transform"
21
+ require "munge/core/transform_scope_factory"
22
+ require "munge/core/write"
13
23
  require "munge/application"
24
+ require "munge/runner"
14
25
 
15
26
  module Munge
16
27
  # Your code goes here...
data/munge.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Zach Ahn"]
10
10
  spec.email = ["zach.ahn@gmail.com"]
11
11
 
12
- spec.summary = "A piping-inspired static site generator"
12
+ spec.summary = "Static site generator aiming to simplify complex build rules"
13
13
  spec.homepage = "https://github.com/zachahn/munge"
14
14
  spec.license = "MIT"
15
15
 
@@ -21,10 +21,17 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.10"
24
+ spec.add_development_dependency "bundler", "~> 1.9"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
26
  spec.add_development_dependency "minitest", "~> 5.8"
27
+ spec.add_development_dependency "fakefs", "~> 0.6"
28
+ spec.add_development_dependency "redcarpet", "~> 3.3"
27
29
  spec.add_development_dependency "rubocop", "~> 0.32"
30
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
31
+ spec.add_development_dependency "simplecov", "~> 0.10"
28
32
 
33
+ spec.add_runtime_dependency "image_optim", "~> 0.21"
34
+ spec.add_runtime_dependency "image_optim_pack", "~> 0.2"
35
+ spec.add_runtime_dependency "thor", "~> 0.19"
29
36
  spec.add_runtime_dependency "tilt", "~> 2.0"
30
37
  end
data/seeds/Gemfile.tt ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in munge.gemspec
4
+ gem 'munge', '~> <%= Munge::VERSION %>'
data/seeds/config.yml ADDED
@@ -0,0 +1,9 @@
1
+ source: src
2
+ output: dest
3
+ data: data.yml
4
+ layouts: layouts
5
+ index: index.html
6
+ binary_extensions:
7
+ - png
8
+ - gif
9
+ - jpg
data/seeds/data.yml ADDED
@@ -0,0 +1 @@
1
+ ---
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Munge</title>
6
+ </head>
7
+ <body>
8
+ <%= yield %>
9
+ </body>
10
+ </html>
data/seeds/rules.rb ADDED
@@ -0,0 +1,5 @@
1
+ app.source
2
+ .select { |item| item.id == "index" }
3
+ .each { |item| item.route = "/" }
4
+ .each { |item| item.layout = "default" }
5
+ .each { |item| item.transform }
@@ -0,0 +1 @@
1
+ <h1>Welcome</h1>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: munge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Ahn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-09-15 00:00:00.000000000 Z
11
+ date: 2015-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '1.9'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '1.9'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fakefs
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: redcarpet
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.3'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rubocop
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +94,76 @@ dependencies:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0.32'
97
+ - !ruby/object:Gem::Dependency
98
+ name: codeclimate-test-reporter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.10'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.10'
125
+ - !ruby/object:Gem::Dependency
126
+ name: image_optim
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.21'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.21'
139
+ - !ruby/object:Gem::Dependency
140
+ name: image_optim_pack
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.2'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: thor
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.19'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.19'
69
167
  - !ruby/object:Gem::Dependency
70
168
  name: tilt
71
169
  requirement: !ruby/object:Gem::Requirement
@@ -83,7 +181,8 @@ dependencies:
83
181
  description:
84
182
  email:
85
183
  - zach.ahn@gmail.com
86
- executables: []
184
+ executables:
185
+ - munge
87
186
  extensions: []
88
187
  extra_rdoc_files: []
89
188
  files:
@@ -95,15 +194,37 @@ files:
95
194
  - LICENSE.txt
96
195
  - README.md
97
196
  - Rakefile
197
+ - exe/munge
98
198
  - lib/munge.rb
99
199
  - lib/munge/application.rb
100
200
  - lib/munge/attribute/content.rb
101
201
  - lib/munge/attribute/metadata.rb
102
202
  - lib/munge/attribute/path.rb
103
- - lib/munge/item.rb
104
- - lib/munge/source.rb
203
+ - lib/munge/cli.rb
204
+ - lib/munge/core/source.rb
205
+ - lib/munge/core/source/item_factory.rb
206
+ - lib/munge/core/transform.rb
207
+ - lib/munge/core/transform_scope_factory.rb
208
+ - lib/munge/core/write.rb
209
+ - lib/munge/helper.rb
210
+ - lib/munge/helper/find.rb
211
+ - lib/munge/helper/rendering.rb
212
+ - lib/munge/item/base.rb
213
+ - lib/munge/item/binary.rb
214
+ - lib/munge/item/text.rb
215
+ - lib/munge/item/virtual.rb
216
+ - lib/munge/runner.rb
217
+ - lib/munge/transformer/image_optim.rb
218
+ - lib/munge/transformer/tilt.rb
219
+ - lib/munge/transformer/tilt/scope.rb
105
220
  - lib/munge/version.rb
106
221
  - munge.gemspec
222
+ - seeds/Gemfile.tt
223
+ - seeds/config.yml
224
+ - seeds/data.yml
225
+ - seeds/layouts/default.html.erb
226
+ - seeds/rules.rb
227
+ - seeds/src/index.html
107
228
  homepage: https://github.com/zachahn/munge
108
229
  licenses:
109
230
  - MIT
@@ -127,5 +248,5 @@ rubyforge_project:
127
248
  rubygems_version: 2.4.5
128
249
  signing_key:
129
250
  specification_version: 4
130
- summary: A piping-inspired static site generator
251
+ summary: Static site generator aiming to simplify complex build rules
131
252
  test_files: []
data/lib/munge/item.rb DELETED
@@ -1,47 +0,0 @@
1
- module Munge
2
- class Item
3
- def self.create(source_abspath, file_abspath)
4
- path = Munge::Attribute::Path.new(source_abspath, file_abspath)
5
- content = Munge::Attribute::Content.new(File.read(file_abspath))
6
- metadata = Munge::Attribute::Metadata.new(file_abspath)
7
-
8
- new(path, content, metadata)
9
- end
10
-
11
- def initialize(path, content, metadata)
12
- @path = path
13
- @content = content
14
- @metadata = metadata
15
- @route = nil
16
- @layout = nil
17
- end
18
-
19
- attr_reader :path, :metadata
20
- attr_accessor :route, :layout
21
-
22
- def content
23
- @content.content
24
- end
25
-
26
- def content=(new_content)
27
- @content.content = new_content
28
- end
29
-
30
- def info
31
- @content.frontmatter
32
- end
33
-
34
- def rendered_content
35
- Tilt
36
- .templates_for(@path.relative)
37
- .inject(content) do |content, engine|
38
- renderer = engine.new { content }
39
- renderer.render(nil, info)
40
- end
41
- end
42
-
43
- def rendered_output
44
- rendered_content
45
- end
46
- end
47
- end
data/lib/munge/source.rb DELETED
@@ -1,22 +0,0 @@
1
- module Munge
2
- class Source
3
- include Enumerable
4
-
5
- def initialize(source_abspath)
6
- @source_abspath = source_abspath
7
- @pattern = File.join(source_abspath, "**", "*")
8
-
9
- @items = Dir[@pattern]
10
- .reject { |item_path| File.directory?(item_path) }
11
- .map { |item_path| Item.create(source_abspath, item_path) }
12
- end
13
-
14
- def each
15
- return enum_for(:each) unless block_given?
16
-
17
- @items.each do |item|
18
- yield item
19
- end
20
- end
21
- end
22
- end