lib/squib/commands/make_sprue.rb in squib-0.14.1 vs lib/squib/commands/make_sprue.rb in squib-0.14.2

- old
+ new

@@ -1,275 +1,275 @@ -require 'fileutils' -require 'pathname' -require 'highline' -require 'bigdecimal' -require 'yaml' -require_relative 'data/template_option' - -module Squib - # Squib's command-line option - module Commands - # Generate a template definition file that can be used for - # +save_templated_sheet+ - # - # @api public - class MakeSprue - # :nodoc: - # @api private - def process(args, input = $stdin, output = $stdout) - # Get definitions from the user - @option = prompt(input, output) - - @printable_edge_right = ( - @option.sheet_width - @option.sheet_margin.right) - @printable_edge_bottom = ( - @option.sheet_height - @option.sheet_margin.bottom) - @card_iter_x = @option.card_width + @option.card_gap.horizontal - @card_iter_y = @option.card_height + @option.card_gap.vertical - - # Recalculate the sheet margin if the sheet alignment is in the center - if @option.sheet_align == :center - @option.sheet_margin = recalculate_center_align_sheet - end - - # We would now have to output the file - YAML.dump generate_template, File.new(@option.output_file, 'w') - end - - private - - # Accept user input that defines the template. - def prompt(input, output) - option = TemplateOption.new - cli = HighLine.new(input, output) - - option.unit = cli.choose do |menu| - menu.prompt = 'What measure unit should we use? ' - menu.choice(:in) - menu.choice(:cm) - menu.choice(:mm) - end - - cli.choose do |menu| - menu.prompt = 'What paper size you are using? ' - menu.choice('A4, portrait') do - option.sheet_width = convert_measurement_value( - 210, :mm, option.unit - ) - option.sheet_height = convert_measurement_value( - 297, :mm, option.unit - ) - end - menu.choice('A4, landscape') do - option.sheet_width = convert_measurement_value( - 297, :mm, option.unit - ) - option.sheet_height = convert_measurement_value( - 210, :mm, option.unit - ) - end - menu.choice('US letter, portrait') do - option.sheet_width = convert_measurement_value( - 8.5, :in, option.unit - ) - option.sheet_height = convert_measurement_value( - 11, :in, option.unit - ) - end - menu.choice('US letter, landscape') do - option.sheet_width = convert_measurement_value( - 11, :in, option.unit - ) - option.sheet_height = convert_measurement_value( - 8.5, :in, option.unit - ) - end - menu.choice('Custom size') do - option.sheet_width = cli.ask( - "Custom paper width? (#{option.unit}) ", Float - ) - option.sheet_height = cli.ask( - "Custom paper height? (#{option.unit}) ", Float - ) - end - end - - option.sheet_margin = cli.ask( - "Sheet margins? (#{option.unit}) " - ) do |q| - q.validate = /^((\d+\.\d+|\d+) ){0,3}(\d+\.\d+|\d+)/ - end - option.sheet_align = cli.choose do |menu| - menu.prompt = 'How to align cards on sheet? [left] ' - menu.choice(:left) - menu.choice(:right) - menu.choice(:center) - menu.default = :left - end - - option.card_width = cli.ask( - "Card width? (#{option.unit}) ", Float - ) { |q| q.above = 0 } - option.card_height = cli.ask( - "Card height? (#{option.unit}) ", Float - ) { |q| q.above = 0 } - option.card_gap = cli.ask( - "Gap between cards? (#{option.unit}) " - ) { |q| q.validate = /^((\d+\.\d+|\d+))(\s+(\d+\.\d+|\d+))?/ } - - option.card_ordering = cli.choose do |menu| - menu.prompt = 'How to layout your cards? [rows]' - menu.choice(:rows, text: 'In rows') - menu.choice(:columns, text: 'In columns') - menu.default = :rows - end - - option.crop_lines = cli.choose do |menu| - menu.prompt = 'Generate crop lines? [true]' - menu.choice(:true) - menu.choice(:false) - menu.default = :true - end - - option.output_file = cli.ask('Output to? ') do |q| - q.validate = lambda do |path_str| - path = Pathname.new path_str - if path.exist? - path.writable? && !path.directory? - else - path.dirname.writable? - end - end - - q.responses[:not_valid] = ( - 'The filename specified is not a writable file or is a directory.' - ) - q.default = 'template.yml' - end - - option - end - - def convert_measurement_value(val, from_unit, to_unit) - return val if from_unit == to_unit - - if from_unit == :in - val_mm = val * 25.4 - elsif from_unit == :cm - val_mm = val * 10.0 - end - - if to_unit == :in - val_mm / 25.4 - elsif to_unit == :cm - val_mm / 10.0 - else - val_mm - end - end - - def generate_template - x = @option.sheet_margin.left - y = @option.sheet_margin.top - cards = [] - horizontal_crop_lines = Set.new - vertical_crop_lines = Set.new - - while ( - x + @card_iter_x < @printable_edge_right && - y + @card_iter_y < @printable_edge_bottom) - xpos = x + @option.card_gap.horizontal - ypos = y + @option.card_gap.vertical - cards.push( - 'x' => "#{xpos}#{@option.unit}", - 'y' => "#{ypos}#{@option.unit}" - ) - - # Append the crop lines - vertical_crop_lines.add xpos - vertical_crop_lines.add xpos + @option.card_width - horizontal_crop_lines.add ypos - horizontal_crop_lines.add ypos + @option.card_height - - # Calculate the next iterator - if @option.card_ordering == :rows - x, y = next_card_pos_row(x, y) - elsif @option.card_ordering == :columns - x, y = next_card_pos_col(x, y) - else - raise RunTimeException, 'Invalid card ordering value received' - end - end - - output = { - 'sheet_width' => "#{@option.sheet_width}#{@option.unit}", - 'sheet_height' => "#{@option.sheet_height}#{@option.unit}", - 'card_width' => "#{@option.card_width}#{@option.unit}", - 'card_height' => "#{@option.card_height}#{@option.unit}", - 'cards' => cards - } - - if @option.crop_lines == :true - lines = [] - vertical_crop_lines.each do |val| - lines.push( - 'type' => :vertical, 'position' => "#{val}#{@option.unit}" - ) - end - horizontal_crop_lines.each do |val| - lines.push( - 'type' => :horizontal, 'position' => "#{val}#{@option.unit}" - ) - end - output['crop_line'] = { 'lines' => lines } - end - - # Return the output data - output - end - - def recalculate_center_align_sheet - # We will still respect the user specified margins - printable_width = ( - @option.sheet_width - @option.sheet_margin.left - - @option.sheet_margin.right) - num_of_cols, remainder = printable_width.divmod(@card_iter_x) - if ( - @option.card_gap.horizontal > 0 && - remainder < @option.card_gap.horizontal) - num_of_cols -= 1 - end - - new_hor_margin = ( - (@option.sheet_width - num_of_cols * @card_iter_x - - @option.card_gap.horizontal) / 2) - Margin.new [ - @option.sheet_margin.top, - new_hor_margin, - @option.sheet_margin.bottom - ] - end - - def next_card_pos_row(x, y) - x += @card_iter_x - - if (x + @card_iter_x) > @printable_edge_right - x = @option.sheet_margin.left - y += @card_iter_y - end - - [x, y] - end - - def next_card_pos_col(x, y) - y += @card_iter_y - - if (y + @card_iter_y) > @printable_edge_bottom - x += @card_iter_x - y = @option.sheet_margin.top - end - - [x, y] - end - end - end -end +require 'fileutils' +require 'pathname' +require 'highline' +require 'bigdecimal' +require 'yaml' +require_relative 'data/template_option' + +module Squib + # Squib's command-line option + module Commands + # Generate a template definition file that can be used for + # +save_templated_sheet+ + # + # @api public + class MakeSprue + # :nodoc: + # @api private + def process(args, input = $stdin, output = $stdout) + # Get definitions from the user + @option = prompt(input, output) + + @printable_edge_right = ( + @option.sheet_width - @option.sheet_margin.right) + @printable_edge_bottom = ( + @option.sheet_height - @option.sheet_margin.bottom) + @card_iter_x = @option.card_width + @option.card_gap.horizontal + @card_iter_y = @option.card_height + @option.card_gap.vertical + + # Recalculate the sheet margin if the sheet alignment is in the center + if @option.sheet_align == :center + @option.sheet_margin = recalculate_center_align_sheet + end + + # We would now have to output the file + YAML.dump generate_template, File.new(@option.output_file, 'w') + end + + private + + # Accept user input that defines the template. + def prompt(input, output) + option = TemplateOption.new + cli = HighLine.new(input, output) + + option.unit = cli.choose do |menu| + menu.prompt = 'What measure unit should we use? ' + menu.choice(:in) + menu.choice(:cm) + menu.choice(:mm) + end + + cli.choose do |menu| + menu.prompt = 'What paper size you are using? ' + menu.choice('A4, portrait') do + option.sheet_width = convert_measurement_value( + 210, :mm, option.unit + ) + option.sheet_height = convert_measurement_value( + 297, :mm, option.unit + ) + end + menu.choice('A4, landscape') do + option.sheet_width = convert_measurement_value( + 297, :mm, option.unit + ) + option.sheet_height = convert_measurement_value( + 210, :mm, option.unit + ) + end + menu.choice('US letter, portrait') do + option.sheet_width = convert_measurement_value( + 8.5, :in, option.unit + ) + option.sheet_height = convert_measurement_value( + 11, :in, option.unit + ) + end + menu.choice('US letter, landscape') do + option.sheet_width = convert_measurement_value( + 11, :in, option.unit + ) + option.sheet_height = convert_measurement_value( + 8.5, :in, option.unit + ) + end + menu.choice('Custom size') do + option.sheet_width = cli.ask( + "Custom paper width? (#{option.unit}) ", Float + ) + option.sheet_height = cli.ask( + "Custom paper height? (#{option.unit}) ", Float + ) + end + end + + option.sheet_margin = cli.ask( + "Sheet margins? (#{option.unit}) " + ) do |q| + q.validate = /^((\d+\.\d+|\d+) ){0,3}(\d+\.\d+|\d+)/ + end + option.sheet_align = cli.choose do |menu| + menu.prompt = 'How to align cards on sheet? [left] ' + menu.choice(:left) + menu.choice(:right) + menu.choice(:center) + menu.default = :left + end + + option.card_width = cli.ask( + "Card width? (#{option.unit}) ", Float + ) { |q| q.above = 0 } + option.card_height = cli.ask( + "Card height? (#{option.unit}) ", Float + ) { |q| q.above = 0 } + option.card_gap = cli.ask( + "Gap between cards? (#{option.unit}) " + ) { |q| q.validate = /^((\d+\.\d+|\d+))(\s+(\d+\.\d+|\d+))?/ } + + option.card_ordering = cli.choose do |menu| + menu.prompt = 'How to layout your cards? [rows]' + menu.choice(:rows, text: 'In rows') + menu.choice(:columns, text: 'In columns') + menu.default = :rows + end + + option.crop_lines = cli.choose do |menu| + menu.prompt = 'Generate crop lines? [true]' + menu.choice(:true) + menu.choice(:false) + menu.default = :true + end + + option.output_file = cli.ask('Output to? ') do |q| + q.validate = lambda do |path_str| + path = Pathname.new path_str + if path.exist? + path.writable? && !path.directory? + else + path.dirname.writable? + end + end + + q.responses[:not_valid] = ( + 'The filename specified is not a writable file or is a directory.' + ) + q.default = 'template.yml' + end + + option + end + + def convert_measurement_value(val, from_unit, to_unit) + return val if from_unit == to_unit + + if from_unit == :in + val_mm = val * 25.4 + elsif from_unit == :cm + val_mm = val * 10.0 + end + + if to_unit == :in + val_mm / 25.4 + elsif to_unit == :cm + val_mm / 10.0 + else + val_mm + end + end + + def generate_template + x = @option.sheet_margin.left + y = @option.sheet_margin.top + cards = [] + horizontal_crop_lines = Set.new + vertical_crop_lines = Set.new + + while ( + x + @card_iter_x < @printable_edge_right && + y + @card_iter_y < @printable_edge_bottom) + xpos = x + @option.card_gap.horizontal + ypos = y + @option.card_gap.vertical + cards.push( + 'x' => "#{xpos}#{@option.unit}", + 'y' => "#{ypos}#{@option.unit}" + ) + + # Append the crop lines + vertical_crop_lines.add xpos + vertical_crop_lines.add xpos + @option.card_width + horizontal_crop_lines.add ypos + horizontal_crop_lines.add ypos + @option.card_height + + # Calculate the next iterator + if @option.card_ordering == :rows + x, y = next_card_pos_row(x, y) + elsif @option.card_ordering == :columns + x, y = next_card_pos_col(x, y) + else + raise RunTimeException, 'Invalid card ordering value received' + end + end + + output = { + 'sheet_width' => "#{@option.sheet_width}#{@option.unit}", + 'sheet_height' => "#{@option.sheet_height}#{@option.unit}", + 'card_width' => "#{@option.card_width}#{@option.unit}", + 'card_height' => "#{@option.card_height}#{@option.unit}", + 'cards' => cards + } + + if @option.crop_lines == :true + lines = [] + vertical_crop_lines.each do |val| + lines.push( + 'type' => :vertical, 'position' => "#{val}#{@option.unit}" + ) + end + horizontal_crop_lines.each do |val| + lines.push( + 'type' => :horizontal, 'position' => "#{val}#{@option.unit}" + ) + end + output['crop_line'] = { 'lines' => lines } + end + + # Return the output data + output + end + + def recalculate_center_align_sheet + # We will still respect the user specified margins + printable_width = ( + @option.sheet_width - @option.sheet_margin.left - + @option.sheet_margin.right) + num_of_cols, remainder = printable_width.divmod(@card_iter_x) + if ( + @option.card_gap.horizontal > 0 && + remainder < @option.card_gap.horizontal) + num_of_cols -= 1 + end + + new_hor_margin = ( + (@option.sheet_width - num_of_cols * @card_iter_x - + @option.card_gap.horizontal) / 2) + Margin.new [ + @option.sheet_margin.top, + new_hor_margin, + @option.sheet_margin.bottom + ] + end + + def next_card_pos_row(x, y) + x += @card_iter_x + + if (x + @card_iter_x) > @printable_edge_right + x = @option.sheet_margin.left + y += @card_iter_y + end + + [x, y] + end + + def next_card_pos_col(x, y) + y += @card_iter_y + + if (y + @card_iter_y) > @printable_edge_bottom + x += @card_iter_x + y = @option.sheet_margin.top + end + + [x, y] + end + end + end +end