munge 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 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