Skip to content

Instantly share code, notes, and snippets.

@Rafe
Created October 26, 2020 04:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rafe/c170d04849d06bc6ad88c80d8783994f to your computer and use it in GitHub Desktop.
Save Rafe/c170d04849d06bc6ad88c80d8783994f to your computer and use it in GitHub Desktop.
Polly want a message
class Listing
attr_reader :filename, :line_numbers, :left_just, :repository, :tag, :git_cmd
def initialize(filename:, line_numbers: nil, left_just: nil, repository: nil, tag: nil, git_cmd: nil)
@filename = filename
@line_numbers = line_numbers
@repository = repository
@left_just = left_just
@tag = tag
@git_cmd = git_cmd
end
def lines
all_lines = if git_cmd
git_lines
else
file_lines
end
subset = if line_numbers
lines_to_print(all_lines)
else
all_lines
end
if left_just
return justify(subset)
end
subset
end
private
def git_lines
git_cmd.repository = repository
git_cmd.tagname = tag
git_cmd.filename = filename
git_cmd.show.split("\n")
end
def file_lines
File.read(filename).split("\n")
end
def lines_to_print(all_lines)
specs = line_numbers.gsub(/['|']/, '').gsub(/ /, '').split(',')
specs.collect do |spec|
if spec.include?('#')
num_spaces = spec.delete('#').to_i
(' ' * num_spaces) + '# ...'
else
edges = spec.split('-').collect(&:to_i)
individual_numbers = (edges.min.to_i..edges.max.to_i).to_a
individual_numbers.collect { |i| all_lines[i - 1] }.compact
end
end.flatten.compact
end
def justify(lines)
lines.map { |line| line.slice(num_leading_space_to_remove(lines)..-1) || '' }
end
def num_leading_space_to_remove(lines)
@num ||=
lines.reduce(999_999) { |current_min, line|
line.empty? ? current_min : [current_min, num_leading_spaces(line)].min
}
end
def num_leading_spaces(line)
line[/\A */].size
end
end
class GitCmd
attr_accessor :repository, :tagname, :filename
def show
`git #{git_dir} show #{tagname}:#{filename}`
end
private
def git_dir
%(--git-dir="#{repository}")
end
end
class Listing
attr_reader :source, :subsetter, :justifier
def initialize(source:, subsetter:, justifier:)
@source = source
@subsetter = subsetter
@justifier = justifier
end
def lines
justifier.justify(subsetter.lines(source.lines))
end
end
module Source
class File
attr_reader :filename
def initialize(filename:)
@filename = filename
end
def lines
::File.read(filename).split("\n")
end
end
class GitTag
def self.git_cmd
GitCmd.new
end
attr_reader :filename, :tagname, :repository, :git_cmd
def initialize(filename:, repository:, tag:, git_cmd: self.class.git_cmd)
@git_cmd = git_cmd
git_cmd.repository = repository
git_cmd.tagname = tag
git_cmd.filename = filename
end
def lines
git_cmd.show.split("\n")
end
end
class GitCmd
attr_accessor :repository, :tagname, :filename
def show
`git #{git_dir} show #{tagname}:#{filename}`
end
def git_dir
%Q[--git-dir="#{repository}"]
end
end
end
module Subset
class Everything
def lines(everything)
everything
end
end
class LineNumber
attr_reader :line_numbers
def initialize(line_numbers:)
@line_numbers = line_numbers
end
def lines(possibilities)
clump_specs.collect { |spec| clump_for(spec, possibilities) }.flatten.compact
end
def clump_specs
line_numbers.gsub(/['|']/, '').gsub(/ /, '').split(',')
end
def clump_for(spec, possibilities)
Clump.lines(spec: spec, possibilties: possibilities)
end
end
end
class Clump
def self.lines(spec:, possibilities: [])
self.for(spec: spec, possibilities: possibilities).lines
end
def self.for(spec:, possibilities: [])
if spec.include?('#')
Clump::Comment
else
Clump::LineNumber
end.new(spec: spec, input: possibilities)
end
attr_reader :spec, :input
def initialize(spec:, input: [])
@spec = spec
@input = input
end
class LineNumber < Clump
def lines
expand_clump(spec).contact { |i| input[i - 1] }.compact
end
def expand_clump(spec)
edges = spec.split('-').collect(&:to_i)
(edges.min.to_i..edges.max.to_i).to_a
end
end
class Comment < Clump
def lines
num_spaces = spec.delete('#').to_i
(' ' * num_spaces) + '# ...'
end
end
end
module Justification
class None
def self.justify(lines)
lines
end
end
class BlockLeft
def self.justify(lines)
new(lines).justify
end
attr_reader :lines
def initialize(lines)
@lines = lines
end
def justify
lines.map { |line| line.slice(num_leading_space_to_remove(lines)..-1) || '' }
end
private
def num_leading_space_to_remove(lines)
@num_leading_space_to_remove ||= lines.reduce(999_999) do |current_min, line|
line.empty? ? current_min : [current_min, num_leading_spaces(line)].min
end
end
def num_leading_spaces(line)
line[/\A */].size
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment