class Frag::App
Attributes
status[R]
Public Class Methods
new(args, input=STDIN, output=STDOUT, error=STDERR)
click to toggle source
# File lib/frag/app.rb, line 8 def initialize(args, input=STDIN, output=STDOUT, error=STDERR) @input, @output, @error = input, output, error @status = 0 @version_printed = false @state = State.new('frag:', 'frag end', '#', '', nil, nil) begin parser.parse!(args) rescue OptionParser::InvalidOption => e return error e.message end args.size > 0 || @version_printed or return error "no files given" @input_paths = args end
Public Instance Methods
run()
click to toggle source
# File lib/frag/app.rb, line 26 def run return @status if @status != 0 global_state = @state.dup @input_paths.each do |input_path| @state = global_state.dup manage_files(input_path) do |input, output| process(input, output) end end @status end
Private Instance Methods
error(message, status=1)
click to toggle source
# File lib/frag/app.rb, line 42 def error(message, status=1) @error.puts "error: #{message}" @status = status false end
manage_files(input_path) { |input, output or return| ... }
click to toggle source
# File lib/frag/app.rb, line 121 def manage_files(input_path) File.exist?(input_path) or return error "file not found: #{input_path}" File.file?(input_path) or return error "not a file: #{input_path}" File.readable?(input_path) or return error "cannot read file: #{input_path}" File.writable?(input_path) or return error "cannot write file: #{input_path}" tempfile = nil success = nil open(input_path) do |input| tempfile = Tempfile.open('frag') do |output| yield input, output or return output end end if @state.backup_prefix || @state.backup_suffix backup_path = "#{@state.backup_prefix}#{File.expand_path(input_path)}#{@state.backup_suffix}" FileUtils.mkdir_p File.dirname(backup_path) FileUtils.cp input_path, backup_path end FileUtils.cp tempfile.path, input_path end
parser()
click to toggle source
# File lib/frag/app.rb, line 52 def parser @parser ||= OptionParser.new do |parser| parser.banner = "USAGE: #$0 [options] file ..." parser.separator "\nOptions:" parser.on '-b', '--begin DELIMITER', "Delimiter that begins each generated fragment. Default: 'frag:'" do |value| @state.beginning = value end parser.on '-e', '--end DELIMITER', "Delimiter that ends each generated fragment. Default: 'frag end'" do |value| @state.ending = value end parser.on '-l', '--leader STRING', "String that precedes each begin or end delimiter. Default: '#'" do |value| if parser.parsing_subconfig warn "-l / --leader is unnecessary in $frag-config line" end @state.leader = value end parser.on '-t', '--trailer STRING', "String that succeeds each begin or end delimiter. Default: ''" do |value| if parser.parsing_subconfig warn "-t / --trailer is unnecessary in $frag-config line" end @state.trailer = value end parser.on '-p', '--backup-prefix PREFIX', "Back up original files with the given prefix. May be a directory." do |value| @state.backup_prefix = value end parser.on '-s', '--backup-suffix SUFFIX', "Back up original files with the given suffix." do |value| @state.backup_suffix = value end parser.on '-v', '--version', "" do @output.puts "Frag version #{Frag::VERSION}" @version_printed = true end parser.separator <<-EOS.gsub(/^ *\|/, '') | |## Embedded options | |Options may also be embedded in the file itself via a line that |contains "$frag-config:". Example: | | <!-- $frag-config: -p ~/.frag-backups/ --> | |Note that the leader and trailer are always taken from the strings |that preceed the "$frag-config" and succeed the last option |respectively. They need not be set with --leader and --trailer. | EOS class << parser attr_accessor :parsing_subconfig def parse_subconfig!(args) self.parsing_subconfig = true # OptionParser will error on an argument like like "-->". if args.last =~ /\A--?(?:[^0-9a-zA-Z]|\z)/ last_arg = args.pop parse!(args) args << last_arg else parse!(args) end ensure self.parsing_subconfig = false end end end end
process(input, output)
click to toggle source
# File lib/frag/app.rb, line 147 def process(input, output) region_start = nil command = nil while (line = input.gets) unless region_start output.puts line end case line when @state.begin_line region_start.nil? or return error "#{input.lineno}: nested region" command = $1 region_start = input.lineno when @state.end_line region_start or return error "#{input.lineno}: unmatched end delimiter" output.puts `#{command}` if !$?.success? return error "#{region_start}: failed: (#{$?.exitstatus}) #{command}" end region_start = nil output.puts line when /\A\s*(?:(\S+)\s*)?\$frag-config:\s*(.*)$/ args = Shellwords.shellsplit($2) begin parser.parse_subconfig!(args) rescue OptionParser::InvalidOption => e return error "#{input.lineno}: #{e.message}" end args.size <= 1 or return error "#{input.lineno}: unexpected argument(s): #{args[0..-2].join(' ')}" @state.leader = $1 || '' @state.trailer = args.first || '' end end if region_start return error "#{region_start}: unmatched begin delimiter" end true end
warn(message)
click to toggle source
# File lib/frag/app.rb, line 48 def warn(message) @error.puts "warning: #{message}" end