lib/squib/layout_parser.rb in squib-0.14.2 vs lib/squib/layout_parser.rb in squib-0.14.3.pre1

- old
+ new

@@ -1,138 +1,138 @@ -require 'yaml' - -module Squib - # Internal class for handling layouts - # @api private - class LayoutParser - - def initialize(dpi = 300) - @dpi = dpi - end - - # Load the layout file(s), if exists - # @api private - def load_layout(files, initial = {}) - layout = initial - 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 - # note: YAML.load_file returns false on empty file - yml = layout.merge(YAML.load_file(thefile) || {}) - 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 - - private - - # Determine the file path of the built-in layout file - def builtin(file) - "#{File.dirname(__FILE__)}/builtin/layouts/#{file}" - end - - # Process the extends recursively - # :nodoc: - # @api private - def 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| - handle_relative_operators(parent_val, child_val) - end - h = h.merge(from_extends) do |key, older_sibling, younger_sibling| - # In general, go with the younger sibling. - # UNLESS that younger sibling had a relative operator, in which use the - # (already computed) relative operator applied, which lands in older_sibling - # See bug 244. - sibling = younger_sibling - %w(+= -= *= /=).each do |op| - sibling = older_sibling if younger_sibling.to_s.strip.start_with? op - end - sibling - end - end - return h - end - - def handle_relative_operators(parent_val, child_val) - if child_val.to_s.strip.start_with?('+=') - add_parent_child(parent_val, child_val) - elsif child_val.to_s.strip.start_with?('-=') - sub_parent_child(parent_val, child_val) - elsif child_val.to_s.strip.start_with?('*=') - mul_parent_child(parent_val, child_val) - elsif child_val.to_s.strip.start_with?('/=') - div_parent_child(parent_val, child_val) - else - child_val # child overrides parent when merging, no += - end - end - - def add_parent_child(parent, child) - parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f - child_pixels = Args::UnitConversion.parse(child.sub('+=', ''), @dpi).to_f - parent_pixels + child_pixels - end - - def sub_parent_child(parent, child) - parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f - child_pixels = Args::UnitConversion.parse(child.sub('-=', ''), @dpi).to_f - parent_pixels - child_pixels - end - - def mul_parent_child(parent, child) - parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f - child_float = child.sub('*=', '').to_f - parent_pixels * child_float - end - - def div_parent_child(parent, child) - parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f - child_float = child.sub('/=', '').to_f - parent_pixels / child_float - 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 has_extends?(yml, key) - !!yml[key] && yml[key].key?('extends') - end - - # Checks if we have any absentee parents - # @api private - def 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 assert_not_visited(key, visited) - if visited.key? key - raise "Invalid layout: circular extends with '#{key}'" - end - end - - end -end +require 'yaml' + +module Squib + # Internal class for handling layouts + # @api private + class LayoutParser + + def initialize(dpi = 300) + @dpi = dpi + end + + # Load the layout file(s), if exists + # @api private + def load_layout(files, initial = {}) + layout = initial + 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 + # note: YAML.load_file returns false on empty file + yml = layout.merge(YAML.load_file(thefile) || {}) + 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 + + private + + # Determine the file path of the built-in layout file + def builtin(file) + "#{File.dirname(__FILE__)}/builtin/layouts/#{file}" + end + + # Process the extends recursively + # :nodoc: + # @api private + def 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| + handle_relative_operators(parent_val, child_val) + end + h = h.merge(from_extends) do |key, older_sibling, younger_sibling| + # In general, go with the younger sibling. + # UNLESS that younger sibling had a relative operator, in which use the + # (already computed) relative operator applied, which lands in older_sibling + # See bug 244. + sibling = younger_sibling + %w(+= -= *= /=).each do |op| + sibling = older_sibling if younger_sibling.to_s.strip.start_with? op + end + sibling + end + end + return h + end + + def handle_relative_operators(parent_val, child_val) + if child_val.to_s.strip.start_with?('+=') + add_parent_child(parent_val, child_val) + elsif child_val.to_s.strip.start_with?('-=') + sub_parent_child(parent_val, child_val) + elsif child_val.to_s.strip.start_with?('*=') + mul_parent_child(parent_val, child_val) + elsif child_val.to_s.strip.start_with?('/=') + div_parent_child(parent_val, child_val) + else + child_val # child overrides parent when merging, no += + end + end + + def add_parent_child(parent, child) + parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f + child_pixels = Args::UnitConversion.parse(child.sub('+=', ''), @dpi).to_f + parent_pixels + child_pixels + end + + def sub_parent_child(parent, child) + parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f + child_pixels = Args::UnitConversion.parse(child.sub('-=', ''), @dpi).to_f + parent_pixels - child_pixels + end + + def mul_parent_child(parent, child) + parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f + child_float = child.sub('*=', '').to_f + parent_pixels * child_float + end + + def div_parent_child(parent, child) + parent_pixels = Args::UnitConversion.parse(parent, @dpi).to_f + child_float = child.sub('/=', '').to_f + parent_pixels / child_float + 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 has_extends?(yml, key) + !!yml[key] && yml[key].key?('extends') + end + + # Checks if we have any absentee parents + # @api private + def 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 assert_not_visited(key, visited) + if visited.key? key + raise "Invalid layout: circular extends with '#{key}'" + end + end + + end +end