First we will create a new gem scaffold using the bundler gem that comes with Ruby.
$ bundle gem tofu
$ cd tofu
$ subl .
Now we can edit the gemspec file to add metadata to our gem.
So lets actually code something, how about being able to count all the lines of code we have written.
# lib/tofu.rb
require "tofu/version"
module Tofu
class LineCounter
def initialize(base_dir)
@base_dir = base_dir
end
def code_files(exts)
glob = File.join(File.expand_path(@base_dir), "**/*.{#{exts}}")
Dir[glob].reject {|f| File.directory?(f) }
end
def lines(file)
IO.read(file).lines.count
end
def all_lines(exts)
files = code_files(exts)
line_count = files.map {|f| lines(f)}.inject(:+)
file_count = files.size
return line_count, file_count
end
end
end
Now we can test this in irb
$ irb -Ilib
>> require "tofu"
>> t = Tofu::LineCounter.new("~/Box/Dev")
>> t.all_lines('rb,py')
But we don't want to use irb, we want a cool executable like bundler. For this we create something in the bin folder.
#!/usr/bin/env ruby
require "tofu"
t = Tofu::LineCounter.new(ARGV[0] || Dir.pwd)
lines, files = t.all_lines(ARGV[1] || 'rb,py,m,cpp,h')
puts "Found #{lines} lines across #{files} files."
Now see in the gemspec, bundler won't recognize our files until we add them to git.
$ git add -A
$ git commit -m "Initial stuff"
Now we can try out our command.
$ bundle
$ bundle exec tofu
$ bundle exec tofu ~/Box/Dev
$ bundle exec tofu ~/Box/Dev rb,py
Now lets add a dependency to make things snazzy. We just add a line to our gemspec to declare it and then use it in our executable file.
# tofu.gemspec
spec.add_runtime_dependency 'colored'
# bin/tofu
require "colored"
puts "Found #{lines.to_s.blue} lines across #{files.to_s.red} files."
For extra credit let's add snazziness, a unix command can trivially count lines but we can count lines of code by stripping empty lines and comments.
def lines(file)
count = 0
IO.foreach(file) do |line|
# TODO: fix stupid UTF-8 stuff, Oh Lord Matz, forgive me for using rescue nil
count += 1 unless line.empty? || (line =~ /^\S*(#|\/\/)/) rescue nil
end
count
end
Now we want to be able to install this on our computer and our friends so lets package it.
$ rake build
$ rake install
$ rake release # don't run this