Skip to content

Instantly share code, notes, and snippets.

@jbrains
Forked from CoryFoy/gist:9441665
Last active August 29, 2015 13:57
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jbrains/9451941 to your computer and use it in GitHub Desktop.
# SMELL I don't like the name gemfile_lock_file, but I don't know
# what else to call it. I want to distinguish it from Gemfile.
def extract_gems_from_gemfile_lock_file(contents)
gems = []
# Extract all the non-empty lines between and excluding 'specs:' and 'PLATFORMS'
contents.each_line do |line|
line = line.strip
# It takes a few seconds to understand this algorithm,
# but I can't yet justify replacing it with a functional
# approach. Again, it depends what the reader understands
# better.
# If we're going to let iterating and filtering stay
# intertwined like this, I'm glad we've separated it from
# the rest of the code.
break if line.include?("PLATFORMS")
next if line.include?("GEM")
next if line.include?("remote:")
next if line.include?("specs:")
next if line.empty?
gems.push(line.split(' ').first)
end
return gems
end
# Guess what? Now independent of "gem" concept. More reusable. MAGIC!
# Guess what? Almost dead-simple wrapper around command line tool. Cohesive. SRP. Nice.
def count_lines_in_file(file)
output = `wc -l #{file}`
# ASSERT: output is of the form <whitespace><line count><whitespace><filename>
# We could turn this comment into code by matching with a regex, which some
# would find clearer and others less clear. I could do either.
line_count_text = output.strip.split(' ').first
return line_count_text.to_i
end
# SMELL Depends on globals like 'puts' and `` (execute process).
def count_lines_for_gem(gem)
puts "Processing #{gem}"
gem_filenames = `gem contents #{gem}`.split
# If you prefer to 'inject', then feel free to 'inject'.
# Either way, the name duplication disappears.
line_count_for_this_gem = gem_filenames.map { |each| count_lines_in_file(each) }.reduce(:+)
puts " LOC: #{line_count_for_this_gem}"
return line_count_for_this_gem
end
total = extract_gems_from_gemfile_lock_file(File.read("Gemfile.lock"))
.map { |each| count_lines_for_gem(each) }.reduce(:+)
puts "Total Lines: #{total}"
@jbrains
Copy link
Author

jbrains commented Mar 9, 2014

If you don't care about the interim line count in each gem, then we can remove the duplicate count_lines concept, replacing the whole thing with this, in approximate Haskell, of course:

sum ((count_lines . filenames_in_gem . gems_in_gemfile_lock) gemfile_lock)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment