class Middleman::ExtensionLessHelper::Extension

Constants

EXTENSION_MAP

Public Class Methods

new(app, options_hash={}, &block) click to toggle source
Calls superclass method
# File lib/middleman-extensionless-helper/extension.rb, line 11
def initialize(app, options_hash={}, &block)
  super

  require 'digest/sha2'
  require 'fileutils'
  require 'ostruct'

  @target = create_target(options.target)
end

Public Instance Methods

after_build(builder) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 56
def after_build(builder)

  # Rename target files in the build directory as we expect.
  #  e.g. build/foo.html -> build/foo
  @target.each do |target|
    rename_build_file(target.build, target.expect)

  # SHOULD do after above the process, because a build path in a target object is referred.
    present_status(builder, target)

  end

end
after_configuration() click to toggle source

Hooks

# File lib/middleman-extensionless-helper/extension.rb, line 28
def after_configuration

  # Avoid applying a layout to target files.
  # #page requires a URL having a absolute path from the root that is not the source directory
  # but the web site. Besides, because it's the URL, a file name in it must be the same as MM
  # names in a build process. Hence the URL looks like "/foo.html"(the original file is "foo").
  @target.each do |target|
    app.page File.join('', target.build), :layout => false
  end

end
before_build(builder) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 40
def before_build(builder)

  # Rename target files in the build directory for avoiding a "create" message by MM.
  #  e.g. build/foo -> build/foo.html
  # Because target files are renamed by this extension in a previous build process, MM cannot
  # find them and assumes that they are newly created and displays a "create" message.
  # So, restore a name of target files to one which MM names in a build process.
  @target.each do |target|
    rename_build_file(target.expect, target.build)
  end

  # SHOULD do after above the process, because a build path in a target object is referred.
  inject_target_state

end

Private Instance Methods

convert_source_path(source) click to toggle source

Internals

# File lib/middleman-extensionless-helper/extension.rb, line 77
def convert_source_path(source)
  # This isn't a smart way, but shouldn't use #split|Regexp because there're some "edge" cases.

  template_exts = EXTENSION_MAP.keys

  first_ext = File.extname(source).downcase
  return {} unless template_exts.include?(first_ext)

  expected_path = source.sub(/#{Regexp.quote(first_ext)}$/i, '')
  return {} if File.extname(expected_path) != ''

  base_name = File.basename expected_path
  return {} if base_name.start_with?('.') && !base_name.match(/^\.ht(?:access|passwd)$/)

  build_ext = EXTENSION_MAP[first_ext]
  {build: (expected_path + build_ext), expect: expected_path}
end
create_target(target) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 95
def create_target(target)

  # SHOULD NOT check an existence of file in here, because files in a source directory are
  # changed, created and removed until starting a build process.
  [target].flatten.inject([]) do |stack, path|
    paths = convert_source_path(path)
    (stack << OpenStruct.new(paths.merge(original: path))) if !paths.empty?
    stack
  end

end
digest_of(path) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 107
def digest_of(path)
  Digest::SHA256.file(path).hexdigest
end
inject_target_state() click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 111
def inject_target_state
  state_skel = {created: false, removed: false, active: true, digest: ''}

  @target.each do |target|
    path_in_source = path_of target.original, :source
    path_in_build = path_of target.build, :build
    in_source = File.file? path_in_source
    in_build = File.file? path_in_build
    state = OpenStruct.new state_skel.dup

    case true
    when  in_source &&  in_build  then  # no-op               # File is updated or identical.
    when  in_source && !in_build  then  state.created = true  # File is created.
    when !in_source &&  in_build  then  state.removed = true  # File is removed.
    else                                state.active = false  # No file.
    end

    state.digest = digest_of(path_in_build) if in_build
    target.state = state
  end
end
path_of(path_crumb, type, absolute = true) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 133
def path_of(path_crumb, type, absolute = true)

  # SHOULD get path to the build|source directory at any time of need, because the
  # configuration value of :build_dir|:source can be updated anytime.
  id = type.to_sym == :build ? :build_dir : :source
  path = File.join(app.config[id], path_crumb)
  absolute ? File.expand_path(path) : path
end
present_status(builder, target) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 142
def present_status(builder, target)
  build_path = ->(path){ path_of path, :build, false }
  message = "#{build_path.call target.build} => #{build_path.call target.expect}"

  status, message, color = \
    case true
    when target.state.created
      ['rename', "#{message} (create)", :green]
    when target.state.removed
      ['remove', "#{build_path.call target.expect}", :red]
    when target.state.active
      digest_of(path_of(target.expect, :build)) == target.state.digest \
        ? ['rename', "#{message} (identical)", :blue] \
        : ['rename', "#{message} (update)", :yellow]
    else
      ['no-target', path_of(target.original, :source, false), :magenta]
    end

  builder.say_status "EH:#{status}", message, color
end
rename_build_file(from, to) click to toggle source
# File lib/middleman-extensionless-helper/extension.rb, line 163
def rename_build_file(from, to)
  src, dest = [path_of(from, :build), path_of(to, :build)]
  FileUtils.mv(src, dest) if File.file?(src) && !File.exist?(dest)
end