You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.8 KiB
91 lines
2.8 KiB
require 'yaml' |
|
|
|
module Squib |
|
# Internal class for handling layouts |
|
#@api private |
|
class LayoutParser |
|
|
|
# Load the layout file(s), if exists |
|
# @api private |
|
def self.load_layout(files) |
|
layout = {} |
|
Squib::logger.info { " using layout(s): #{files}" } |
|
Array(files).each do |file| |
|
thefile = file |
|
thefile = builtin(file) unless File.exists?(file) |
|
if File.exists? thefile |
|
yml = layout.merge(YAML.load_file(thefile) || {}) #load_file returns false on empty file |
|
yml.each do |key, value| |
|
layout[key] = recurse_extends(yml, key, {}) |
|
end |
|
else |
|
Squib::logger.error { "Layout file not found: #{file}. Skipping..." } |
|
end |
|
end |
|
return layout |
|
end |
|
|
|
# Determine the file path of the built-in layout file |
|
def self.builtin(file) |
|
"#{File.dirname(__FILE__)}/layouts/#{file}" |
|
end |
|
|
|
# Process the extends recursively |
|
# :nodoc: |
|
# @api private |
|
def self.recurse_extends(yml, key, visited ) |
|
assert_not_visited(key, visited) |
|
return yml[key] unless has_extends?(yml, key) |
|
return yml[key] unless parents_exist?(yml, key) |
|
visited[key] = key |
|
parent_keys = [yml[key]['extends']].flatten |
|
h = {} |
|
parent_keys.each do |parent_key| |
|
from_extends = yml[key].merge(recurse_extends(yml, parent_key, visited)) do |key, child_val, parent_val| |
|
if child_val.to_s.strip.start_with?('+=') |
|
parent_val + child_val.sub('+=','').strip.to_f |
|
elsif child_val.to_s.strip.start_with?('-=') |
|
parent_val - child_val.sub('-=','').strip.to_f |
|
else |
|
child_val #child overrides parent when merging, no += |
|
end |
|
end |
|
h = h.merge(from_extends) do |key, older_sibling, younger_sibling| |
|
younger_sibling #when two siblings have the same entry, the "younger" (lower one) overrides |
|
end |
|
end |
|
return h |
|
end |
|
|
|
# Does this layout entry have an extends field? |
|
# i.e. is it a base-case or will it need recursion? |
|
# :nodoc: |
|
# @api private |
|
def self.has_extends?(yml, key) |
|
!!yml[key] && yml[key].key?('extends') |
|
end |
|
|
|
# Checks if we have any absentee parents |
|
# @api private |
|
def self.parents_exist?(yml, key) |
|
exists = true |
|
Array(yml[key]['extends']).each do |parent| |
|
unless yml.key?(parent) |
|
exists = false unless |
|
Squib.logger.error "Processing layout: '#{key}' attempts to extend a missing '#{yml[key]['extends']}'" |
|
end |
|
end |
|
return exists |
|
end |
|
|
|
# Safeguard against malformed circular extends |
|
# :nodoc: |
|
# @api private |
|
def self.assert_not_visited(key, visited) |
|
if visited.key? key |
|
raise "Invalid layout: circular extends with '#{key}'" |
|
end |
|
end |
|
|
|
end |
|
end
|
|
|