Commit 8a6f9a1

mo khan <mo@mokhan.ca>
2014-09-26 20:40:36
replace custom commandline parsing with thor.
1 parent 6d8252b
bin/tfa
@@ -1,4 +1,4 @@
 #!/usr/bin/env ruby
 require 'tfa'
 
-puts TFA::Console.new.run(ARGV)
+TFA::CLI.start(ARGV)
lib/tfa/cli.rb
@@ -0,0 +1,29 @@
+require "thor"
+
+module TFA
+  class CLI < Thor
+    package_name "TFA"
+    class_option :filename
+
+    desc "add NAME SECRET", "add a new secret to the database"
+    def add(name, secret)
+      AddCommand.new(storage).run([name, secret])
+    end
+
+    desc "show NAME", "shows the secret for the given key"
+    def show(name)
+      ShowCommand.new(storage).run([name])
+    end
+
+    desc "totp NAME", "generate a Time based One Time Password"
+    def totp(name)
+      TotpCommand.new(storage).run([name])
+    end
+
+    private
+
+    def storage
+      @storage ||= Storage.new(filename: options[:filename] || 'tfa')
+    end
+  end
+end
lib/tfa/console.rb
@@ -1,26 +0,0 @@
-module TFA
-  class Console
-    def initialize(filename = "tfa")
-      @storage = Storage.new(filename)
-    end
-
-    def run(arguments)
-      command_name = arguments.first
-      command_for(command_name).run(arguments - [command_name])
-    end
-
-    private
-
-    def command_for(command_name)
-      registry[command_name].call
-    end
-
-    def registry
-      Hash.new { |x, y| lambda { UsageCommand.new(@storage) } }.tap do |commands|
-        commands['add'] = lambda { AddCommand.new(@storage) }
-        commands['show'] = lambda { ShowCommand.new(@storage) }
-        commands['totp'] = lambda { TotpCommand.new(@storage) }
-      end
-    end
-  end
-end
lib/tfa/storage.rb
@@ -1,6 +1,6 @@
 module TFA
   class Storage
-    def initialize(filename)
+    def initialize(filename:)
       @storage = PStore.new(File.join(Dir.home, ".#{filename}.pstore"))
     end
 
lib/tfa.rb
@@ -5,5 +5,5 @@ require "tfa/add_command"
 require "tfa/show_command"
 require "tfa/totp_command"
 require "tfa/usage_command"
-require "tfa/console"
+require "tfa/cli"
 require "tfa/storage"
spec/lib/console_spec.rb
@@ -1,26 +1,20 @@
 module TFA
-  describe Console do
-    subject { Console.new('testing') }
+  describe CLI do
+    subject { CLI.new }
     let(:secret) { ::ROTP::Base32.random_base32 }
 
     describe "#run" do
       context "when adding a key" do
         it "saves a new secret" do
-          subject.run(["add", "development", secret])
-          expect(subject.run(["show", "development"])).to eql(secret)
+          subject.add("development", secret)
+          expect(subject.show("development")).to eql(secret)
         end
       end
 
       context "when getting a one time password" do
         it "creates a totp for a certain key" do
-          subject.run(["add", "development", secret])
-          expect(subject.run(["totp", "development"])).to_not be_nil
-        end
-      end
-
-      context "when running an unknown command" do
-        it "returns the usage" do
-          expect(subject.run([])).to_not be_nil
+          subject.add("development", secret)
+          expect(subject.totp("development")).to_not be_nil
         end
       end
     end
spec/lib/show_command_spec.rb
@@ -1,7 +1,7 @@
 module TFA
   describe ShowCommand do
     subject { ShowCommand.new(storage) }
-    let(:storage) { Storage.new(SecureRandom.uuid) }
+    let(:storage) { Storage.new(filename: SecureRandom.uuid) }
 
     describe "#run" do
       context "when looking up the secret for a specific key" do
spec/lib/totp_command_spec.rb
@@ -1,8 +1,7 @@
 module TFA
   describe TotpCommand do
     subject { TotpCommand.new(storage) }
-    let(:storage) { Storage.new(Tempfile.new('test').path) }
-    let(:storage) { Storage.new(SecureRandom.uuid) }
+    let(:storage) { Storage.new(filename: SecureRandom.uuid) }
 
     def code_for(secret)
       ::ROTP::TOTP.new(secret).now
tfa.gemspec
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
   spec.require_paths = ["lib"]
 
   spec.add_dependency "rotp"
+  spec.add_dependency "thor"
   spec.add_development_dependency "bundler", "~> 1.6"
   spec.add_development_dependency "rake"
   spec.add_development_dependency "rspec"