From 923f3465758b97520b208e2d00d7c143d1d04799 Mon Sep 17 00:00:00 2001 From: Andy Meneely Date: Tue, 28 Apr 2015 20:31:53 -0400 Subject: [PATCH] Redesigning how config files are read, stored, and delegated With the new design, we take the load off of deck.rb and simply delegate methods over to the new conf.rb. This means that things like `antialias` is now available as a method to the normal Squib scripts for easy checking (without being mutable). Squib::Conf also handles parsing and defaults, and any potential input validation we need to do in the future. Typographer is also set up now as a deck-wide configuration. This may change in the future if we want typography customization per-command, although that seems like a strange use case. Lots of tests for this one, and lots of cross-cutting concerns in this commit. This commit also includes some tweaks to rspec tests, including tagging of slow tests for a `rake spec_fastonly` Conflicts: spec/samples/samples_regression_spec.rb spec/spec_helper.rb squib.sublime-project --- Rakefile | 4 + lib/squib/api/image.rb | 4 +- lib/squib/args/typographer.rb | 35 ++++---- lib/squib/card.rb | 10 +-- lib/squib/conf.rb | 114 ++++++++++++++++++++++++ lib/squib/constants.rb | 32 ------- lib/squib/deck.rb | 60 +++---------- lib/squib/graphics/save_doc.rb | 2 +- lib/squib/graphics/text.rb | 6 +- lib/squib/input_helpers.rb | 4 +- samples/custom-config.yml | 1 - samples/custom_config.rb | 2 +- spec/conf_spec.rb | 29 ++++++ spec/data/conf/basic.yml | 0 spec/data/conf/empty.yml | 1 + spec/graphics/graphics_images_spec.rb | 89 +++++++++--------- spec/graphics/graphics_shapes_spec.rb | 84 ++++++++--------- spec/graphics/graphics_text_spec.rb | 5 +- spec/samples/samples_regression_spec.rb | 4 +- spec/spec_helper.rb | 8 ++ squib.sublime-project | 38 +++++++- 21 files changed, 330 insertions(+), 202 deletions(-) create mode 100644 lib/squib/conf.rb create mode 100644 spec/conf_spec.rb create mode 100644 spec/data/conf/basic.yml create mode 100644 spec/data/conf/empty.yml diff --git a/Rakefile b/Rakefile index ddc3e2c..8745d37 100644 --- a/Rakefile +++ b/Rakefile @@ -20,6 +20,10 @@ end RSpec::Core::RakeTask.new(:spec) +RSpec::Core::RakeTask.new(:spec_fastonly) do |t| + t.rspec_opts = "--tag ~slow" +end + task doc: [:yarddoc, :apply_google_analytics] YARD::Rake::YardocTask.new(:yarddoc) do |t| diff --git a/lib/squib/api/image.rb b/lib/squib/api/image.rb index b311879..a2caff6 100644 --- a/lib/squib/api/image.rb +++ b/lib/squib/api/image.rb @@ -22,7 +22,7 @@ module Squib # @api public def png(opts = {}) opts = needs(opts, [:range, :files, :x, :y, :width, :height, :alpha, :layout, :blend, :angle, :mask]) - Dir.chdir(@img_dir) do + Dir.chdir(img_dir) do @progress_bar.start('Loading PNG(s)', opts[:range].size) do |bar| opts[:range].each do |i| @cards[i].png(opts[:file][i], @@ -57,7 +57,7 @@ module Squib # @api public def svg(opts = {}) p = needs(opts,[:range, :files, :svgid, :force_svgid, :x, :y, :width, :height, :layout, :alpha, :blend, :angle, :mask]) - Dir.chdir(@img_dir) do + Dir.chdir(img_dir) do @progress_bar.start('Loading SVG(s)', p[:range].size) do |bar| p[:range].each do |i| unless p[:force_id][i] && p[:id][i].to_s.empty? diff --git a/lib/squib/args/typographer.rb b/lib/squib/args/typographer.rb index ab753c8..9768c57 100644 --- a/lib/squib/args/typographer.rb +++ b/lib/squib/args/typographer.rb @@ -3,13 +3,16 @@ module Squib module Args class Typographer - def initialize(config = CONFIG_DEFAULTS) - @config = config + def initialize(config = Conf::DEFAULTS) + %w(lsquote ldquote rsquote rdquote smart_quotes + em_dash en_dash ellipsis).each do |var| + instance_variable_set("@#{var}", config[var]) + end end def process(str) - str = explicit_replacements(str) - str = smart_quotes(str) if @config['smart_quotes'] + str = explicit_replacements(str.to_s) + str = smart_quotes(str) if @smart_quotes str end @@ -53,58 +56,58 @@ module Squib # Straightforward replace def left_curly(str) - str.gsub('``', @config['ldquote']) + str.gsub('``', @ldquote) end # Straightforward replace def right_curly(str) - str.gsub(%{''}, @config['rdquote']) + str.gsub(%{''}, @rdquote) end # A quote between two letters is an apostraphe def apostraphize(str) - str.gsub(/(\w)(\')(\w)/, '\1' + @config['rsquote'] + '\3') + str.gsub(/(\w)(\')(\w)/, '\1' + @rsquote + '\3') end # Straightforward replace def ellipsificate(str) - str.gsub('...', @config['ellipsis']) + str.gsub('...', @ellipsis) end # Straightforward replace def en_dash(str) - str.gsub('--', @config['en_dash']) + str.gsub('--', @en_dash) end # Straightforward replace def em_dash(str) - str.gsub('---', @config['em_dash']) + str.gsub('---', @em_dash) end # Quote next to non-whitespace curls def right_double_quote(str) - str.gsub(/(\S)(\")/, '\1' + @config['rdquote']) + str.gsub(/(\S)(\")/, '\1' + @rdquote) end # Quote next to non-whitespace curls def left_double_quote(str) - str.gsub(/(\")(\S)/, @config['ldquote'] + '\2') + str.gsub(/(\")(\S)/, @ldquote + '\2') end # Handle the cases where a double quote is next to a single quote def single_inside_double_quote(str) - str.gsub(/(\")(\')(\S)/, @config['ldquote'] + @config['lsquote'] + '\3') - .gsub(/(\")(\')(\S)/, '\1' + @config['rsquote'] + @config['rdquote']) + str.gsub(/(\")(\')(\S)/, @ldquote + @lsquote + '\3') + .gsub(/(\")(\')(\S)/, '\1' + @rsquote + @rdquote) end # Quote next to non-whitespace curls def right_single_quote(str) - str.gsub(/(\S)(\')/, '\1' + @config['rsquote']) + str.gsub(/(\S)(\')/, '\1' + @rsquote) end # Quote next to non-whitespace curls def left_single_quote(str) - str.gsub(/(\')(\S)/, @config['lsquote'] + '\2') + str.gsub(/(\')(\S)/, @lsquote + '\2') end end diff --git a/lib/squib/card.rb b/lib/squib/card.rb index 25f83d0..91f0cd7 100644 --- a/lib/squib/card.rb +++ b/lib/squib/card.rb @@ -16,21 +16,21 @@ module Squib # :nodoc: # @api private - def initialize(deck, width, height, backend=:memory, index=-1) + def initialize(deck, width, height, index=-1) @deck = deck @width = width @height = height - @backend = backend + @backend = deck.backend @svgfile = "#{deck.dir}/#{deck.prefix}#{deck.count_format % index}.svg" - @cairo_surface = make_surface(@svgfile, backend) + @cairo_surface = make_surface(@svgfile, @backend) @cairo_context = Squib::Graphics::CairoContextWrapper.new(Cairo::Context.new(@cairo_surface)) - @cairo_context.antialias = ANTIALIAS_OPTS[(@deck.antialias.downcase)] || 'subpixel' + @cairo_context.antialias = deck.antialias end # :nodoc: # @api private def make_surface(svgfile, backend) - case backend + case backend.downcase.to_sym when :memory Cairo::ImageSurface.new(@width, @height) when :svg diff --git a/lib/squib/conf.rb b/lib/squib/conf.rb new file mode 100644 index 0000000..6de5c9c --- /dev/null +++ b/lib/squib/conf.rb @@ -0,0 +1,114 @@ +require 'squib' +require 'forwardable' +require 'squib/args/typographer' + +module Squib + # @api private + class Conf + + DEFAULTS = { + 'antialias' => 'best', + 'backend' => 'memory', + 'count_format' => SYSTEM_DEFAULTS[:count_format], + 'custom_colors' => {}, + 'dir' => SYSTEM_DEFAULTS[:dir], + 'hint' => :none, + 'img_dir' => '.', + 'progress_bars' => false, + 'ldquote' => "\u201C", # UTF8 chars + 'rdquote' => "\u201D", + 'lsquote' => "\u2018", + 'rsquote' => "\u2019", + 'em_dash' => "\u2014", + 'en_dash' => "\u2013", + 'ellipsis' => "\u2026", + 'smart_quotes' => true, + 'text_hint' => 'off', + } + + #Translate the hints to the methods. + ANTIALIAS_OPTS = { + nil => 'subpixel', + 'best' => 'subpixel', + 'good' => 'gray', + 'fast' => 'gray', + 'gray' => 'gray', + 'subpixel' => 'subpixel' + } + + def initialize(config_hash = DEFAULTS) + @config_hash = config_hash + @typographer = Args::Typographer.new(config_hash) + normalize_antialias + end + + # FIXME REMOVE THIS as part of refactoring + # Delegate [] to our hash + # @api private + # def [](key) + # @config_hash[key] + # end + + # Load the configuration file, if exists, overriding hardcoded defaults + # @api private + def self.load(file) + yaml = {} + if File.exists? file + Squib::logger.info { " using config: #{file}" } + yaml = YAML.load_file(file) || {} + end + Conf.new(DEFAULTS.merge(yaml)) + end + + def to_s + "Conf: #{@config_hash.to_s}" + end + + def img_dir + @config_hash['img_dir'] + end + + def text_hint + @config_hash['text_hint'] + end + + def progress_bars + @config_hash['progress_bars'] + end + + def typographer + @typographer + end + + def dir + @config_hash['dir'] + end + + def prefix + @config_hash['prefix'] + end + + def count_format + @config_hash['count_format'] + end + + def antialias + @config_hash['antialias'] + end + + def backend + @config_hash['backend'] + end + + def custom_colors + @config_hash['custom_colors'] + end + + private + + def normalize_antialias + @config_hash['antialias'] = ANTIALIAS_OPTS[@config_hash['antialias'].downcase.strip] + end + + end +end \ No newline at end of file diff --git a/lib/squib/constants.rb b/lib/squib/constants.rb index eb52d19..2b4a675 100644 --- a/lib/squib/constants.rb +++ b/lib/squib/constants.rb @@ -67,38 +67,6 @@ module Squib :y_radius => 0, } - # Squib's configuration defaults - # - # @api public - CONFIG_DEFAULTS = { - 'antialias' => 'best', - 'backend' => 'memory', - 'count_format' => SYSTEM_DEFAULTS[:count_format], - 'custom_colors' => {}, - 'dir' => SYSTEM_DEFAULTS[:dir], - 'dpi' => 300, - 'hint' => :none, - 'img_dir' => '.', - 'progress_bar' => false, - 'ldquote' => "\u201C", # UTF8 chars - 'rdquote' => "\u201D", - 'lsquote' => "\u2018", - 'rsquote' => "\u2019", - 'em_dash' => "\u2014", - 'en_dash' => "\u2013", - 'ellipsis' => "\u2026", - 'smart_quotes' => true, - 'text_hint' => 'off', - } - - #Translate the hints to the methods. - ANTIALIAS_OPTS = { - 'best' => 'subpixel', - 'good' => 'gray', - 'fast' => 'gray', - 'gray' => 'gray', - 'subpixel' => 'subpixel' - } # These are parameters that are intended to be "expanded" across # range if they are singletons. # diff --git a/lib/squib/deck.rb b/lib/squib/deck.rb index e205f91..36ba94d 100644 --- a/lib/squib/deck.rb +++ b/lib/squib/deck.rb @@ -1,5 +1,6 @@ require 'yaml' require 'pp' +require 'forwardable' require 'squib' require 'squib/card' require 'squib/progress' @@ -7,6 +8,7 @@ require 'squib/input_helpers' require 'squib/constants' require 'squib/layout_parser' require 'squib/args/unit_conversion' +require 'squib/conf' # The project module # @@ -19,24 +21,19 @@ module Squib class Deck include Enumerable include Squib::InputHelpers + extend Forwardable - # :nodoc: - # @api private - attr_reader :width, :height - - # :nodoc: - # @api private - attr_reader :cards - - # :nodoc: + # Attributes for the width, height (in pixels) and number of cards + # These are expected to be immuatble for the life of Deck # @api private - attr_reader :text_hint, :antialias + attr_reader :width, :height, :cards + # Delegate these configuration options to the Squib::Conf object + def_delegators :conf, :antialias, :backend, :count_format, :custom_colors, :dir, + :img_dir, :prefix, :text_hint, :typographer # :nodoc: # @api private - attr_reader :layout, :config, :quote_chars - - attr_reader :dir, :prefix, :count_format + attr_reader :layout, :conf # Squib's constructor that sets the immutable properties. # @@ -58,24 +55,16 @@ module Squib # @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) - @antialias = CONFIG_DEFAULTS['antialias'] @dpi = dpi @font = SYSTEM_DEFAULTS[:default_font] @cards = [] @custom_colors = {} - @img_dir = '.' - @progress_bar = Progress.new(false) - @text_hint = :off - @backend = :memory - @dir = SYSTEM_DEFAULTS[:dir] - @prefix = SYSTEM_DEFAULTS[:prefix] - @count_format = SYSTEM_DEFAULTS[:count_format] - @quote_chars = CONFIG_DEFAULTS.select {|k,v| %w(lsquote rsquote ldquote rdquote em_dash en_dash ellipsis smart_quotes).include?(k) } + @conf = Conf.load(config) + @progress_bar = Progress.new(@conf.progress_bars) # FIXME this is evil. Using something different with @ and non-@ show_info(config, layout) - load_config(config) @width = Args::UnitConversion.parse width, dpi @height = Args::UnitConversion.parse height, dpi - cards.times{ |i| @cards << Squib::Card.new(self, @width, @height, @backend, i) } + cards.times{ |i| @cards << Squib::Card.new(self, @width, @height, i) } @layout = LayoutParser.load_layout(layout) if block_given? instance_eval(&block) # here we go. wheeeee! @@ -96,29 +85,6 @@ module Squib @cards.each { |card| block.call(card) } 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) - Squib::logger.info { " using config: #{file}" } - config = 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'] - @backend = (config['backend'].to_s.downcase.strip == 'svg') ? :svg : :memory - @dir = config['dir'] - @prefix = config['prefix'] - @count_format = config['count_format'] - @antialias = config['antialias'] - @quote_chars ||= {} - %w(lsquote rsquote ldquote rdquote smart_quotes em_dash en_dash ellipsis).each do |key| - @quote_chars[key] = config[key] - end - end - end - # Use Logger to show more detail on the run # :nodoc: # @api private diff --git a/lib/squib/graphics/save_doc.rb b/lib/squib/graphics/save_doc.rb index 8cbddac..89dc8c5 100644 --- a/lib/squib/graphics/save_doc.rb +++ b/lib/squib/graphics/save_doc.rb @@ -33,7 +33,7 @@ module Squib cc.translate(x,y) cc.rectangle(p[:trim], p[:trim], card_width, card_height) cc.clip - case card.backend + case card.backend.downcase.to_sym when :memory cc.set_source(card.cairo_surface, 0, 0) cc.paint diff --git a/lib/squib/graphics/text.rb b/lib/squib/graphics/text.rb index 4177032..df54491 100644 --- a/lib/squib/graphics/text.rb +++ b/lib/squib/graphics/text.rb @@ -78,7 +78,7 @@ module Squib def set_font_rendering_opts!(layout) font_options = Cairo::FontOptions.new - font_options.antialias = ANTIALIAS_OPTS[(@deck.antialias.downcase)] || 'gray' + font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase] font_options.hint_metrics = 'on' # TODO make this configurable font_options.hint_style = 'full' # TODO make this configurable layout.context.font_options = font_options @@ -127,7 +127,7 @@ module Squib while (key = next_embed(embed.rules.keys, clean_str)) != nil rule = embed.rules[key] spacing = rule[:width] * Pango::SCALE - index = clean_str.index(key) + index = clean_str.index(key) index = clean_str[0..index].bytesize #convert to byte index (bug #57) str = str.sub(key, "aaa") layout.markup = str @@ -164,7 +164,7 @@ module Squib layout.font_description = font_desc layout.text = str if markup - str = Args::Typographer.new(@deck.quote_chars).process(layout.text) + str = @deck.typographer.process(layout.text) layout.markup = str end diff --git a/lib/squib/input_helpers.rb b/lib/squib/input_helpers.rb index ccfe8b6..fa9dc88 100644 --- a/lib/squib/input_helpers.rb +++ b/lib/squib/input_helpers.rb @@ -130,8 +130,8 @@ module Squib def colorify(opts, nillable=false, key=:color) opts[key].each_with_index do |color, i| unless nillable && color.nil? - if @custom_colors.key? color.to_s - color = @custom_colors[color.to_s] + if custom_colors.key? color.to_s + color = custom_colors[color.to_s] end opts[key][i] = color end diff --git a/samples/custom-config.yml b/samples/custom-config.yml index d23a052..1aa8e97 100644 --- a/samples/custom-config.yml +++ b/samples/custom-config.yml @@ -1,4 +1,3 @@ -dpi: 300 progress_bars: true text_hint: '#FF0000' custom_colors: diff --git a/samples/custom_config.rb b/samples/custom_config.rb index 88445cc..8953f18 100644 --- a/samples/custom_config.rb +++ b/samples/custom_config.rb @@ -4,7 +4,7 @@ Squib::Deck.new(config: 'custom-config.yml') do # Custom color defined in our config background color: :foo - # Hints are turned on in the config file + # Hints can be turned on in the config file text str: 'The Title', x: 0, y: 78, width: 825, font: 'Arial 72', align: :center diff --git a/spec/conf_spec.rb b/spec/conf_spec.rb new file mode 100644 index 0000000..82a798d --- /dev/null +++ b/spec/conf_spec.rb @@ -0,0 +1,29 @@ +require 'squib' +require 'spec_helper' + +describe Squib::Conf do + + it 'parses the project template file just fine' do + conf = Squib::Conf.load(project_template('config.yml')) + expect(conf.backend).to eq(Squib::Conf::DEFAULTS['backend']) + end + + it 'parses an empty file' do + conf = Squib::Conf.load(conf('empty.yml')) + expect(conf.backend).to eq(Squib::Conf::DEFAULTS['backend']) + end + + it 'parses the sample custom config' do + conf = Squib::Conf.load(sample_file('custom-config.yml')) + expect(conf.progress_bars).to be true + expect(conf.text_hint).to eq '#FF0000' + expect(conf.custom_colors).to eq({ 'foo' => '#ccc' }) + expect(conf.img_dir).to eq 'customconfig-imgdir' + end + + it 'normalizes antialias automatically' do + expect(Squib::Conf::DEFAULTS['antialias']).to eq 'best' + expect(Squib::Conf.new.antialias).to eq 'subpixel' + end + +end diff --git a/spec/data/conf/basic.yml b/spec/data/conf/basic.yml new file mode 100644 index 0000000..e69de29 diff --git a/spec/data/conf/empty.yml b/spec/data/conf/empty.yml new file mode 100644 index 0000000..48ddb6f --- /dev/null +++ b/spec/data/conf/empty.yml @@ -0,0 +1 @@ +# Intentionally empty \ No newline at end of file diff --git a/spec/graphics/graphics_images_spec.rb b/spec/graphics/graphics_images_spec.rb index 4769ae0..6b590d8 100644 --- a/spec/graphics/graphics_images_spec.rb +++ b/spec/graphics/graphics_images_spec.rb @@ -3,80 +3,81 @@ require 'squib' describe Squib::Card do - before(:example) do - @deck = double(Squib::Deck) - @context = double(Cairo::Context) - @svg = double(RSVG::Handle) - @png = double(Cairo::ImageSurface) - allow(Cairo::Context).to receive(:new).and_return(@context) - allow(Cairo::ImageSurface).to receive(:from_png).and_return(@png) - allow(Cairo::ImageSurface).to receive(:new).and_return(@png) - allow(RSVG::Handle).to receive(:new_from_file).and_return(@svg) - allow(@deck).to receive(:dir).and_return('_output') - allow(@deck).to receive(:count_format).and_return('%02d') - allow(@deck).to receive(:prefix).and_return('card_') - allow(@deck).to receive(:antialias).and_return('best') + let(:deck) { double(Squib::Deck) } + let(:context) { double(Cairo::Context) } + let(:svg) { double(RSVG::Handle) } + let(:png) { double(Cairo::ImageSurface) } + before(:each) do + allow(Cairo::Context).to receive(:new).and_return(context) + allow(Cairo::ImageSurface).to receive(:from_png).and_return(png) + allow(Cairo::ImageSurface).to receive(:new).and_return(png) + allow(RSVG::Handle).to receive(:new_from_file).and_return(svg) + allow(deck).to receive(:dir).and_return('_output') + allow(deck).to receive(:count_format).and_return('%02d') + allow(deck).to receive(:prefix).and_return('card_') + allow(deck).to receive(:antialias).and_return('subpixel') + allow(deck).to receive(:backend).and_return('memory') end context '#png' do it 'makes all the expected calls on a smoke test' do - expect(@context).to receive(:antialias=).with('subpixel') - expect(@context).to receive(:save).once - expect(@context).to receive(:translate).with(-37, -38).once - expect(@context).to receive(:rotate).with(0.0).once - expect(@context).to receive(:translate).with(37, 38).once - expect(@context).to receive(:set_source).with(@png, 37, 38).once - expect(@context).to receive(:paint).with(0.9).once - expect(@context).to receive(:restore).once + expect(context).to receive(:antialias=).with('subpixel') + expect(context).to receive(:save).once + expect(context).to receive(:translate).with(-37, -38).once + expect(context).to receive(:rotate).with(0.0).once + expect(context).to receive(:translate).with(37, 38).once + expect(context).to receive(:set_source).with(png, 37, 38).once + expect(context).to receive(:paint).with(0.9).once + expect(context).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) # png(file, x, y, alpha, blend, angle) card.png('foo.png', 37, 38, :native, :native, 0.9, :none, 0.0, nil) end it 'sets blend when needed' do - @context.as_null_object - expect(@context).to receive(:operator=).with(:overlay).once + context.as_null_object + expect(context).to receive(:operator=).with(:overlay).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) card.png('foo.png', 37, 38, :native, :native, 0.9, :overlay, 0.0, nil) end end context '#svg' do it 'makes all the expected calls on a smoke test' do - expect(@svg).to receive(:width).and_return(100).twice - expect(@svg).to receive(:height).and_return(100).twice - expect(@context).to receive(:antialias=).with('subpixel').once - expect(@context).to receive(:save).once - expect(@context).to receive(:rotate).with(0.0).once - expect(@context).to receive(:translate).with(37, 38).once - expect(@context).to receive(:scale).with(1.0, 1.0).once - expect(@context).to receive(:render_rsvg_handle).with(@svg, 'id').once - expect(@context).to receive(:restore).once + expect(svg).to receive(:width).and_return(100).twice + expect(svg).to receive(:height).and_return(100).twice + expect(context).to receive(:antialias=).with('subpixel').once + expect(context).to receive(:save).once + expect(context).to receive(:rotate).with(0.0).once + expect(context).to receive(:translate).with(37, 38).once + expect(context).to receive(:scale).with(1.0, 1.0).once + expect(context).to receive(:render_rsvg_handle).with(svg, 'id').once + expect(context).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) # svg(file, id, x, y, width, height, alpha, blend, angle) card.svg('foo.png', 'id', 37, 38, :native, :native, 0.9, :none, 0.0, nil) end it 'sets blend when needed' do - @context.as_null_object - @svg.as_null_object - expect(@context).to receive(:operator=).with(:overlay).once + context.as_null_object + svg.as_null_object + expect(context).to receive(:operator=).with(:overlay).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) card.svg('foo.png', nil, 37, 38, :native, :native, 0.9, :overlay, 0.0, nil) end it 'sets width & height when needed' do - @context.as_null_object - expect(@svg).to receive(:width).and_return(100).once - expect(@svg).to receive(:height).and_return(100).once - expect(@context).to receive(:scale).with(2.0, 3.0).once + context.as_null_object + expect(svg).to receive(:width).and_return(100).once + expect(svg).to receive(:height).and_return(100).once + expect(context).to receive(:scale).with(2.0, 3.0).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) card.svg('foo.png', nil, 37, 38, 200, 300, 0.9, :none, 0.0, nil) end end diff --git a/spec/graphics/graphics_shapes_spec.rb b/spec/graphics/graphics_shapes_spec.rb index b7037d0..c4565ed 100644 --- a/spec/graphics/graphics_shapes_spec.rb +++ b/spec/graphics/graphics_shapes_spec.rb @@ -3,33 +3,35 @@ require 'squib' describe Squib::Card do - def expect_stroke(fill_color, stroke_color, stroke_width) - expect(@context).to receive(:set_source_color).with(stroke_color).once - expect(@context).to receive(:set_line_width).with(stroke_width).once - expect(@context).to receive(:stroke).once - expect(@context).to receive(:set_source_color).with(fill_color).once - expect(@context).to receive(:fill).once + let(:deck) { double(Squib::Deck) } + let(:cxt) { double(Cairo::Context) } + + def expect_stroke(cxt, fill_color, stroke_color, stroke_width) + expect(cxt).to receive(:set_source_color).with(stroke_color).once + expect(cxt).to receive(:set_line_width).with(stroke_width).once + expect(cxt).to receive(:stroke).once + expect(cxt).to receive(:set_source_color).with(fill_color).once + expect(cxt).to receive(:fill).once end before(:each) do - @deck = double(Squib::Deck) - @context = double(Cairo::Context) - allow(Cairo::Context).to receive(:new).and_return(@context) - allow(@deck).to receive(:dir).and_return('_output') - allow(@deck).to receive(:count_format).and_return('%02d') - allow(@deck).to receive(:prefix).and_return('card_') - allow(@deck).to receive(:antialias).and_return('best') + allow(Cairo::Context).to receive(:new).and_return(cxt) + allow(deck).to receive(:dir).and_return('_output') + allow(deck).to receive(:count_format).and_return('%02d') + allow(deck).to receive(:prefix).and_return('card_') + allow(deck).to receive(:antialias).and_return('subpixel') + allow(deck).to receive(:backend).and_return('memory') end context 'rect' do it 'make all the expected calls on a smoke test' do - expect(@context).to receive(:antialias=).with('subpixel') - expect(@context).to receive(:save).once - expect(@context).to receive(:rounded_rectangle).with(37, 38, 50, 100, 10, 15).twice - expect_stroke('#fff', '#f00', 2.0) - expect(@context).to receive(:restore).once + expect(cxt).to receive(:antialias=).with('subpixel') + expect(cxt).to receive(:save).once + expect(cxt).to receive(:rounded_rectangle).with(37, 38, 50, 100, 10, 15).twice + expect_stroke(cxt, '#fff', '#f00', 2.0) + expect(cxt).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) # rect(x, y, width, height, x_radius, y_radius, # fill_color, stroke_color, stroke_width) card.rect(37, 38, 50, 100, 10, 15, '#fff', '#f00', 2.0) @@ -38,14 +40,14 @@ describe Squib::Card do context 'circle' do it 'make all the expected calls on a smoke test' do - expect(@context).to receive(:antialias=).with('subpixel') - expect(@context).to receive(:save).once - expect(@context).to receive(:move_to).with(137, 38) - expect(@context).to receive(:circle).with(37, 38, 100).twice - expect_stroke('#fff', '#f00', 2.0) - expect(@context).to receive(:restore).once + expect(cxt).to receive(:antialias=).with('subpixel') + expect(cxt).to receive(:save).once + expect(cxt).to receive(:move_to).with(137, 38) + expect(cxt).to receive(:circle).with(37, 38, 100).twice + expect_stroke(cxt, '#fff', '#f00', 2.0) + expect(cxt).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) # circle(x, y, radius, # fill_color, stroke_color, stroke_width) card.circle(37, 38, 100, '#fff', '#f00', 2.0) @@ -54,29 +56,29 @@ describe Squib::Card do context 'triangle' do it 'make all the expected calls on a smoke test' do - expect(@context).to receive(:antialias=).with('subpixel') - expect(@context).to receive(:save).once - expect(@context).to receive(:triangle).with(1, 2, 3, 4, 5, 6).twice - expect_stroke('#fff', '#f00', 2.0) - expect(@context).to receive(:restore).once + expect(cxt).to receive(:antialias=).with('subpixel') + expect(cxt).to receive(:save).once + expect(cxt).to receive(:triangle).with(1, 2, 3, 4, 5, 6).twice + expect_stroke(cxt, '#fff', '#f00', 2.0) + expect(cxt).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) card.triangle(1, 2, 3, 4, 5, 6, '#fff', '#f00', 2.0) end end context 'line' do it 'make all the expected calls on a smoke test' do - expect(@context).to receive(:antialias=).with('subpixel') - expect(@context).to receive(:save).once - expect(@context).to receive(:move_to).with(1, 2).once - expect(@context).to receive(:line_to).with(3, 4).once - expect(@context).to receive(:set_source_color).with('#fff').once - expect(@context).to receive(:set_line_width).with(2.0).once - expect(@context).to receive(:stroke).once - expect(@context).to receive(:restore).once + expect(cxt).to receive(:antialias=).with('subpixel') + expect(cxt).to receive(:save).once + expect(cxt).to receive(:move_to).with(1, 2).once + expect(cxt).to receive(:line_to).with(3, 4).once + expect(cxt).to receive(:set_source_color).with('#fff').once + expect(cxt).to receive(:set_line_width).with(2.0).once + expect(cxt).to receive(:stroke).once + expect(cxt).to receive(:restore).once - card = Squib::Card.new(@deck, 100, 150) + card = Squib::Card.new(deck, 100, 150) card.line(1, 2, 3, 4, '#fff', 2.0) end end diff --git a/spec/graphics/graphics_text_spec.rb b/spec/graphics/graphics_text_spec.rb index 065c2d5..6bb7231 100644 --- a/spec/graphics/graphics_text_spec.rb +++ b/spec/graphics/graphics_text_spec.rb @@ -16,6 +16,8 @@ describe Squib::Card, '#text' do allow(deck).to receive(:count_format).and_return('%02d') allow(deck).to receive(:prefix).and_return('card_') allow(deck).to receive(:antialias).and_return('best') + allow(deck).to receive(:antialias).and_return('subpixel') + allow(deck).to receive(:backend).and_return('memory') allow(layout).to receive(:context).and_return(pango_cxt) end @@ -71,7 +73,8 @@ describe Squib::Card, '#text' do allow(deck).to receive(:dir).and_return('_output') allow(deck).to receive(:count_format).and_return('%02d') allow(deck).to receive(:prefix).and_return('card_') - allow(deck).to receive(:antialias).and_return('best') + allow(deck).to receive(:antialias).and_return('subpixel') + allow(deck).to receive(:backend).and_return('memory') end it 'aligns right with strings' do diff --git a/spec/samples/samples_regression_spec.rb b/spec/samples/samples_regression_spec.rb index 1e89522..754fe48 100644 --- a/spec/samples/samples_regression_spec.rb +++ b/spec/samples/samples_regression_spec.rb @@ -13,7 +13,7 @@ describe "Squib samples" do end Dir["#{@SAMPLES_DIR}/**/*.rb"].each do |sample| - it "should execute #{sample} with no errors" do + it "should execute #{sample} with no errors", slow: true do allow(Squib.logger).to receive(:warn) {} allow(ProgressBar).to receive(:create).and_return(Squib::DoNothing.new) load sample @@ -68,7 +68,7 @@ describe "Squib samples" do tgc_proofs.rb units.rb ).each do |sample| - it "has not changed for #{sample}" do + it "has not changed for #{sample}", slow: true do log = StringIO.new mock_cairo(log) load sample diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8f2296f..db702c4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -36,6 +36,14 @@ def xlsx_file(file) "#{File.expand_path(File.dirname(__FILE__))}/data/xlsx/#{file}" end +def project_template(file) + "#{File.expand_path(File.dirname(__FILE__))}/../lib/squib/project_template/#{file}" +end + +def conf(file) + "#{File.expand_path(File.dirname(__FILE__))}/data/conf/#{file}" +end + def overwrite_sample(sample_name, log) # Use this to overwrite the regression with current state File.open(sample_regression_file(sample_name), 'w+:UTF-8') do |f| diff --git a/squib.sublime-project b/squib.sublime-project index e8cf46f..063a2c8 100644 --- a/squib.sublime-project +++ b/squib.sublime-project @@ -12,10 +12,14 @@ "name": "rake", "shell_cmd": "rake", }, - { + { "name": "rake sanity", "shell_cmd": "rake sanity", }, + { + "name": "rake spec_fastonly", + "shell_cmd": "rake spec_fastonly", + }, { "name": "rake run[text_options]", "shell_cmd": "rake run[text_options]", @@ -32,6 +36,10 @@ "name": "rake run[config_text_markup]", "shell_cmd": "rake run[config_text_markup]", }, + { + "name": "rake run[custom_config]", + "shell_cmd": "rake run[custom_config]", + }, { "name": "rspec spec/samples/samples_regression_spec.rb", "shell_cmd": "rspec spec/samples/samples_regression_spec.rb", @@ -48,11 +56,33 @@ "working_dir": "${project_path:${folder}}" }, { - "name": "rspec spec/api/api_data_spec.rb", - "shell_cmd": "rspec spec/api/api_data_spec.rb", "working_dir": "${project_path:${folder}}" }, + { + "name": "rspec spec/graphics/graphics_shapes_spec.rb", + "shell_cmd": "rspec spec/graphics/graphics_shapes_spec.rb", + "working_dir": "${project_path:${folder}}" + }, + { + "name": "rspec spec/conf_spec.rb", + "shell_cmd": "rspec spec/conf_spec.rb", + "working_dir": "${project_path:${folder}}" + }, + { + "name": "rspec spec/graphics/graphics_images_spec.rb", + "shell_cmd": "rspec spec/graphics/graphics_images_spec.rb", + "working_dir": "${project_path:${folder}}" + }, + { + "name": "rspec spec/graphics/graphics_shapes_spec.rb", + "shell_cmd": "rspec spec/graphics/graphics_shapes_spec.rb", + "working_dir": "${project_path:${folder}}" + }, + { + "name": "rspec spec/conf_spec.rb", + "shell_cmd": "rspec spec/conf_spec.rb", - ], + }, + ] }