lib/squib/deck.rb in squib-0.0.3 vs lib/squib/deck.rb in squib-0.0.4

- old
+ new

@@ -1,117 +1,171 @@ -require 'yaml' -require 'pp' -require 'squib' -require 'squib/card' -require 'squib/progress' -require 'squib/input_helpers' -require 'squib/constants' - -# The project module -# -# @api public -module Squib - - # The main interface to Squib. Provides a front-end porcelain whereas the Card class interacts with the graphics plumbing. - # - # @api public - class Deck - include Enumerable - include Squib::InputHelpers - - # :nodoc: - # @api private - attr_reader :width, :height - - # :nodoc: - # @api private - attr_reader :cards - - # :nodoc: - # @api private - attr_reader :text_hint - - # :nodoc: - # @api private - attr_reader :layout, :config - - # Squib's constructor that sets the immutable properties. - # - # This is the starting point for Squib. In providing a block to the constructor, you have access to all of Deck's instance methods. - # The documented methods in Deck are the ones intended for use by most users. - # If your game requires multiple different sizes or orientations, I recommend using multiple `Squib::Deck`s in your `deck.rb`. You can modify the internals of `Squib::Deck` (e.g. `@cards`), but that's not recommended. - # @example - # require 'squib' - # Squib::Deck.new do - # text str: 'Hello, World!' - # end - # - # @param width: [Integer] the width of each card in pixels - # @param height: [Integer] the height of each card in pixels - # @param cards: [Integer] the number of cards in the deck - # @param dpi: [Integer] the pixels per inch when rendering out to PDF or calculating using inches. - # @param config: [String] the Yaml file used for global settings of this deck - # @param layout: [String] the Yaml file used for layouts. - # @param block [Block] the main body of the script. - # @api public - def initialize(width: 825, height: 1125, cards: 1, dpi: 300, config: 'config.yml', layout: nil, &block) - @width=width; @height=height - @dpi = dpi - @font = Squib::SYSTEM_DEFAULTS[:default_font] - @cards = [] - @custom_colors = {} - @img_dir = '.' - @progress_bar = Squib::Progress.new(false) - cards.times{ @cards << Squib::Card.new(self, width, height) } - load_config(config) - @layout = YAML.load_file(layout) unless layout.nil? - if block_given? - instance_eval(&block) - end - end - - # Directly accesses the array of cards in the deck - # - # @api private - def [](key) - @cards[key] - end - - # Iterates over each card in the deck - # - # @api private - def each(&block) - @cards.each { |card| block.call(card) } - end - - # Shows a descriptive place of the location - def location(opts) - opts[:layout] || (" @ #{opts[:x]},#{opts[:y]}") - end - - # Load the configuration file, if exists, overriding hardcoded defaults - # @api private - def load_config(file) - if File.exists?(file) && config = YAML.load_file(file) - config = Squib::CONFIG_DEFAULTS.merge(config) - @dpi = config['dpi'].to_i - @text_hint = config['text_hint'] - @progress_bar.enabled = config['progress_bars'] - @custom_colors = config['custom_colors'] - @img_dir = config['img_dir'] - end - end - - ################## - ### PUBLIC API ### - ################## - require 'squib/api/background' - require 'squib/api/data' - require 'squib/api/image' - require 'squib/api/save' - require 'squib/api/settings' - require 'squib/api/shapes' - require 'squib/api/text' - require 'squib/api/units' - - end +require 'yaml' +require 'pp' +require 'squib' +require 'squib/card' +require 'squib/progress' +require 'squib/input_helpers' +require 'squib/constants' + +# The project module +# +# @api public +module Squib + + # The main interface to Squib. Provides a front-end porcelain whereas the Card class interacts with the graphics plumbing. + # + # @api public + class Deck + include Enumerable + include Squib::InputHelpers + + # :nodoc: + # @api private + attr_reader :width, :height + + # :nodoc: + # @api private + attr_reader :cards + + # :nodoc: + # @api private + attr_reader :text_hint + + # :nodoc: + # @api private + attr_reader :layout, :config + + # Squib's constructor that sets the immutable properties. + # + # This is the starting point for Squib. In providing a block to the constructor, you have access to all of Deck's instance methods. + # The documented methods in Deck are the ones intended for use by most users. + # If your game requires multiple different sizes or orientations, I recommend using multiple `Squib::Deck`s in your `deck.rb`. You can modify the internals of `Squib::Deck` (e.g. `@cards`), but that's not recommended. + # @example + # require 'squib' + # Squib::Deck.new do + # text str: 'Hello, World!' + # end + # + # @param width: [Integer] the width of each card in pixels + # @param height: [Integer] the height of each card in pixels + # @param cards: [Integer] the number of cards in the deck + # @param dpi: [Integer] the pixels per inch when rendering out to PDF or calculating using inches. + # @param config: [String] the file used for global settings of this deck + # @param block [Block] the main body of the script. + # @api public + def initialize(width: 825, height: 1125, cards: 1, dpi: 300, config: 'config.yml', layout: nil, &block) + @width=width; @height=height + @dpi = dpi + @font = Squib::SYSTEM_DEFAULTS[:default_font] + @cards = [] + @custom_colors = {} + @img_dir = '.' + @progress_bar = Squib::Progress.new(false) + @text_hint = :off + cards.times{ @cards << Squib::Card.new(self, width, height) } + load_config(config) + load_layout(layout) + if block_given? + instance_eval(&block) + end + end + + # Directly accesses the array of cards in the deck + # + # @api private + def [](key) + @cards[key] + end + + # Iterates over each card in the deck + # + # @api private + def each(&block) + @cards.each { |card| block.call(card) } + end + + # Shows a descriptive place of the location + def location(opts) + opts[:layout] || (" @ #{opts[:x]},#{opts[:y]}") + end + + # Load the configuration file, if exists, overriding hardcoded defaults + # @api private + def load_config(file) + if File.exists?(file) && config = YAML.load_file(file) + config = Squib::CONFIG_DEFAULTS.merge(config) + @dpi = config['dpi'].to_i + @text_hint = config['text_hint'] + @progress_bar.enabled = config['progress_bars'] + @custom_colors = config['custom_colors'] + @img_dir = config['img_dir'] + end + end + + # Load the layout configuration file, if exists + # @api private + def load_layout(file) + return if file.nil? + @layout = {} + yml = YAML.load_file(file) + yml.each do |key, value| + @layout[key] = recurse_extends(yml, key, {}) + end + 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) + 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 has_extends?(yml, key) + yml[key].key?('extends') + 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 + + ################## + ### PUBLIC API ### + ################## + require 'squib/api/background' + require 'squib/api/data' + require 'squib/api/image' + require 'squib/api/save' + require 'squib/api/settings' + require 'squib/api/shapes' + require 'squib/api/text' + require 'squib/api/units' + + end end \ No newline at end of file