diff --git a/.gitignore b/.gitignore index fbb0a2a..7692abf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.swo *.gem Gemfile.lock +.rspec diff --git a/README.md b/README.md index a625c4b..72df7fc 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,15 @@ alias work_haste="HASTE_SERVER=http://something.com haste" After which you can use `work_haste` to send hastes to that server instead. +## Use as a library + +You can also use `Haste` as a library to upload hastes: + +``` ruby +uploader = Haste::Uploader.new +uploader.upload_raw 'this is my data' # key +``` + ## Windows Support If you'd like an alternative on Windows that supports functionality similar to `pbcopy`, check out Aidan Ryan's [WinHaste](https://github.com/ajryan/WinHaste) project. diff --git a/lib/haste.rb b/lib/haste.rb index 56f4aa8..1da7add 100644 --- a/lib/haste.rb +++ b/lib/haste.rb @@ -2,51 +2,9 @@ require 'bundler/setup' require 'json' require 'uri' require 'rest-client' +require File.dirname(__FILE__) + '/haste/uploader' +require File.dirname(__FILE__) + '/haste/exception' +require File.dirname(__FILE__) + '/haste/cli' module Haste - - DEFAULT_URL = 'http://hastebin.com' - - class CLI - - # Pull all of the data from STDIN - def initialize - if STDIN.tty? - file = ARGV.first - abort 'No input file given' unless file - abort "#{file}: No such path" unless File.exists?(file) - @input = open(file).read - else - @input = STDIN.readlines.join - end - # clean up - @input.rstrip! - end - - # Upload the and output the URL we get back - def start - raw_data = RestClient.post "#{server}/documents", @input - data = JSON.parse(raw_data) - key = data['key'] - STDOUT.send (STDOUT.tty? ? :puts : :print), "#{server}/#{key}" - rescue JSON::ParserError => e - abort "failure parsing response: #{e.message}" - rescue RestClient::Exception => e - abort "failure uploading: #{e.message}" - rescue Errno::ECONNREFUSED => e - abort "failure connecting: #{e.message}" - end - - private - - # Get the server address used - def server - return @server if @server - @server = (ENV['HASTE_SERVER'] || Haste::DEFAULT_URL).dup - @server.chop! if server.end_with?('/') - @server - end - - end - end diff --git a/lib/haste/cli.rb b/lib/haste/cli.rb new file mode 100644 index 0000000..9f690ed --- /dev/null +++ b/lib/haste/cli.rb @@ -0,0 +1,31 @@ +module Haste + + class CLI + + # Create a new uploader + def initialize + @uploader = Uploader.new ENV['HASTE_SERVER'] + end + + # And then handle the basic usage + def start + # Take data in + key = if STDIN.tty? + @uploader.upload_path ARGV.first + else + @uploader.upload_raw STDIN.readlines.join + end + # And write data out + url = "#{@uploader.server_url}/#{key}" + if STDOUT.tty? + STDOUT.puts url + else + STDOUT.print url + end + rescue Exception => e + abort e.message + end + + end + +end diff --git a/lib/haste/exception.rb b/lib/haste/exception.rb new file mode 100644 index 0000000..5cb77cf --- /dev/null +++ b/lib/haste/exception.rb @@ -0,0 +1,4 @@ +module Haste + class Exception < StandardError + end +end diff --git a/lib/haste/uploader.rb b/lib/haste/uploader.rb new file mode 100644 index 0000000..5787213 --- /dev/null +++ b/lib/haste/uploader.rb @@ -0,0 +1,44 @@ +module Haste + + DEFAULT_URL = 'http://hastebin.com' + + class Uploader + + attr_reader :server_url + + def initialize(server_url = nil) + @server_url = server_url || Haste::DEFAULT_URL + @server_url = @server_url.dup + @server_url = @server_url.chop if @server_url.end_with?('/') + end + + # Take in a path and return a key + def upload_path(path) + fail_with 'No input file given' unless path + fail_with "#{path}: No such path" unless File.exists?(path) + upload_raw open(path).read + end + + # Take in data and return a key + def upload_raw(data) + data.rstrip! + raw_data = RestClient.post "#{self.server_url}/documents", data + data = JSON.parse(raw_data) + data['key'] + rescue JSON::ParserError => e + fail_with "failure parsing response: #{e.message}" + rescue RestClient::Exception => e + fail_with "failure uploading: #{e.message}" + rescue Errno::ECONNREFUSED => e + fail_with "failure connecting: #{e.message}" + end + + private + + def fail_with(msg) + raise Exception.new(msg) + end + + end + +end diff --git a/spec/examples/uploader_spec.rb b/spec/examples/uploader_spec.rb new file mode 100644 index 0000000..fde1d4b --- /dev/null +++ b/spec/examples/uploader_spec.rb @@ -0,0 +1,173 @@ +require 'spec_helper' + +describe Haste::Uploader do + + let(:uploader) { base.nil? ? Haste::Uploader.new : Haste::Uploader.new(base) } + + describe :upload_raw do + + let(:data) { 'hello world' } + let(:url) { "#{uploader.server_url}/documents" } + let(:base) { nil } + let(:error_message) do + begin + @key = uploader.upload_raw data + nil # nil otherwise + rescue Haste::Exception => e + e.message + end + end + + context 'with a good response' do + + let(:json) { '{"key":"hello"}' } + + before do + RestClient.should_receive(:post).with(url, data).and_return(json) + end + + it 'should get the key' do + error_message.should be_nil # no error + @key.should == 'hello' + end + + end + + context 'with a bad json response' do + + let(:json) { '{that:not_even_json}' } + + before do + RestClient.should_receive(:post).with(url, data).and_return(json) + end + + it 'should get an error' do + error_message.should start_with 'failure parsing response: ' + end + + end + + context 'with a 404 response' do + + before do + error = RestClient::ResourceNotFound.new + RestClient.should_receive(:post).with(url, data).and_raise(error) + end + + it 'should get an error' do + error_message.should == 'failure uploading: Resource Not Found' + end + + end + + context 'with a non-existent server' do + + before do + error = Errno::ECONNREFUSED + RestClient.should_receive(:post).with(url, data).and_raise(error) + end + + it 'should get the key' do + error_message.should == 'failure connecting: Connection refused' + end + + end + + end + + describe :upload_path do + + let(:base) { nil } + let(:error_message) do + begin + uploader.upload_path path + nil # nil otherwise + rescue Haste::Exception => e + e.message + end + end + + context 'with no path given' do + + let(:path) { nil } + + it 'should have an error' do + error_message.should == 'No input file given' + end + + end + + context 'with an invalid path given' do + + let(:path) { '/tmp/why-do-you-have-a-file-called-john' } + + it 'should have an error' do + error_message.should == "#{path}: No such path" + end + + end + + context 'with a valid path' do + + let(:data) { 'hello world' } + let(:path) { '/tmp/real' } + before { File.write(path, data) } + + before do + uploader.should_receive(:upload_raw).with(data) # check + end + + it 'should not receive an error' do + error_message.should be_nil + end + + end + + end + + describe :server_url do + + let(:server_url) { uploader.server_url } + + context 'with default constructor' do + + let(:base) { nil } + + it 'should use the default url' do + server_url.should == Haste::DEFAULT_URL + end + + end + + context 'with server url passed in constructor' do + + context 'with a trailing slash' do + + before { @string = 'hello/' } + let(:base) { @string } + + it 'should remove the slash' do + server_url.should == @string.chop + end + + it 'should not modify the original' do + @string.should == 'hello/' + end + + end + + context 'with no trailing slash' do + + let(:base) { 'hello' } + + it 'should not chop the url' do + server_url.should == base + end + + end + + end + + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..c4666f0 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../lib/haste'