class Gist::ClipboardError
Public Instance Methods
Get the API URL
# File lib/gist.rb, line 559 def api_url ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_API_URL end
auth token for authentication
@return [String] string value of access token or `nil`, if not found
# File lib/gist.rb, line 67 def auth_token @token ||= AuthTokenFile.read rescue nil end
Get the API base path
# File lib/gist.rb, line 554 def base_path ENV.key?(URL_ENV_NAME) ? GHE_BASE_PATH : GITHUB_BASE_PATH end
Get the command to use for the clipboard action.
@param [Symbol] action either :copy or :paste @return [String] the command to run @raise [Gist::ClipboardError] if no clipboard integration could be found
# File lib/gist.rb, line 512 def clipboard_command(action) command = CLIPBOARD_COMMANDS.keys.detect do |cmd| which cmd end raise ClipboardError, <<-EOT unless command Could not find copy command, tried: #{CLIPBOARD_COMMANDS.values.join(' || ')} EOT action == :copy ? command : CLIPBOARD_COMMANDS[command] end
Copy a string to the clipboard.
@param [String] content @raise [Gist::Error] if no clipboard integration could be found
# File lib/gist.rb, line 466 def copy(content) IO.popen(clipboard_command(:copy), 'r+') { |clip| clip.print content } unless paste == content message = 'Copying to clipboard failed.' if ENV["TMUX"] && clipboard_command(:copy) == 'pbcopy' message << "\nIf you're running tmux on a mac, try http://robots.thoughtbot.com/post/19398560514/how-to-copy-and-paste-with-tmux-on-mac-os-x" end raise Error, message end rescue Error => e raise ClipboardError, e.message + "\nAttempted to copy: #{content}" end
# File lib/gist.rb, line 83 def default_filename "gistfile1.txt" end
# File lib/gist.rb, line 244 def delete_gist(id) id = id.split("/").last url = "#{base_path}/gists/#{id}" access_token = auth_token() if access_token.to_s != '' request = Net::HTTP::Delete.new(url) request["Authorization"] = "token #{access_token}" response = http(api_url, request) else raise Error, "Not authenticated. Use 'gist --login' to login." end if response.code == '204' puts "Deleted!" else raise Error, "Gist with id of #{id} does not exist." end end
# File lib/gist.rb, line 264 def get_gist_pages(url, access_token = "") request = Net::HTTP::Get.new(url) request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) pretty_gist(response) link_header = response.header['link'] if link_header links = Hash[ link_header.gsub(/(<|>|")/, "").split(',').map { |link| link.split('; rel=') } ].invert get_gist_pages(links['next'], access_token) if links['next'] end end
Upload a gist to gist.github.com
@param [String] content the code you'd like to gist @param [Hash] options more detailed options, see
the documentation for {multi_gist}
@see developer.github.com/v3/gists/
# File lib/gist.rb, line 78 def gist(content, options = {}) filename = options[:filename] || default_filename multi_gist({filename => content}, options) end
Run an HTTP operation
@param [URI::HTTP] The URI to which to connect @param [Net::HTTPRequest] The request to make @return [Net::HTTPResponse]
# File lib/gist.rb, line 422 def http(url, request) request['User-Agent'] = USER_AGENT http_connection(url).start do |http| http.request request end rescue Timeout::Error raise "Could not connect to #{api_url}" end
Return HTTP connection
@param [URI::HTTP] The URI to which to connect @return [Net::HTTP]
# File lib/gist.rb, line 400 def http_connection(uri) env = ENV['http_proxy'] || ENV['HTTP_PROXY'] connection = if env proxy = URI(env) Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port) else Net::HTTP.new(uri.host, uri.port) end if uri.scheme == "https" connection.use_ssl = true connection.verify_mode = OpenSSL::SSL::VERIFY_NONE end connection.open_timeout = 10 connection.read_timeout = 10 connection end
# File lib/gist.rb, line 563 def legacy_private_gister? return unless which('git') `git config --global gist.private` =~ /\Ayes|1|true|on\z/i end
# File lib/gist.rb, line 199 def list_all_gists(user = "") url = "#{base_path}" if user == "" access_token = auth_token() if access_token.to_s != '' url << "/gists?per_page=100" get_gist_pages(url, access_token) else raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." end else url << "/users/#{user}/gists?per_page=100" get_gist_pages(url) end end
List all gists(private also) for authenticated user otherwise list public gists for given username (optional argument)
@param [String] user @deprecated
see developer.github.com/v3/gists/#list-gists
# File lib/gist.rb, line 171 def list_gists(user = "") url = "#{base_path}" if user == "" access_token = auth_token() if access_token.to_s != '' url << "/gists" request = Net::HTTP::Get.new(url) request['Authorization'] = "token #{access_token}" response = http(api_url, request) pretty_gist(response) else raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." end else url << "/users/#{user}/gists" request = Net::HTTP::Get.new(url) response = http(api_url, request) pretty_gist(response) end end
Log the user into gist.
This method asks the user for a username and password, and tries to obtain and OAuth2 access token, which is then stored in ~/.gist
@raise [Gist::Error] if something went wrong @param [Hash] credentials login details @option credentials [String] :username @option credentials [String] :password @see developer.github.com/v3/oauth/
# File lib/gist.rb, line 347 def login!(credentials={}) puts "Obtaining OAuth2 access_token from GitHub." loop do print "GitHub username: " username = credentials[:username] || $stdin.gets.strip print "GitHub password: " password = credentials[:password] || begin `stty -echo` rescue nil $stdin.gets.strip ensure `stty echo` rescue nil end puts "" request = Net::HTTP::Post.new("#{base_path}/authorizations") request.body = JSON.dump({ :scopes => [:gist], :note => "The gist gem (#{Time.now})", :note_url => "https://github.com/ConradIrwin/gist" }) request.content_type = 'application/json' request.basic_auth(username, password) response = http(api_url, request) if Net::HTTPUnauthorized === response && response['X-GitHub-OTP'] print "2-factor auth code: " twofa_code = $stdin.gets.strip puts "" request['X-GitHub-OTP'] = twofa_code response = http(api_url, request) end if Net::HTTPCreated === response AuthTokenFile.write JSON.parse(response.body)['token'] puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/tokens" return elsif Net::HTTPUnauthorized === response puts "Error: #{JSON.parse(response.body)['message']}" next else raise "Got #{response.class} from gist: #{response.body}" end end rescue => e raise e.extend Error end
Upload a gist to gist.github.com
@param [Hash] files the code you'd like to gist: filename => content @param [Hash] options more detailed options
@option options [String] :description the description @option options [Boolean] :public (false) is this gist public @option options [Boolean] :anonymous (false) is this gist anonymous @option options [String] :access_token (`File.read(“~/.gist”)`) The OAuth2 access token. @option options [String] :update the URL or id of a gist to update @option options [Boolean] :copy (false) Copy resulting URL to clipboard, if successful. @option options [Boolean] :open (false) Open the resulting URL in a browser. @option options [Boolean] :skip_empty (false) Skip gisting empty files. @option options [Symbol] :output (:all) The type of return value you'd like:
:html_url gives a String containing the url to the gist in a browser :short_url gives a String contianing a git.io url that redirects to html_url :javascript gives a String containing a script tag suitable for embedding the gist :all gives a Hash containing the parsed json response from the server
@return [String, Hash] the return value as configured by options @raise [Gist::Error] if something went wrong
@see developer.github.com/v3/gists/
# File lib/gist.rb, line 110 def multi_gist(files, options={}) if options[:anonymous] raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' else access_token = (options[:access_token] || auth_token()) end json = {} json[:description] = options[:description] if options[:description] json[:public] = !!options[:public] json[:files] = {} files.each_pair do |(name, content)| if content.to_s.strip == "" raise "Cannot gist empty files" unless options[:skip_empty] else name = name == "-" ? default_filename : File.basename(name) json[:files][name] = {:content => content} end end return if json[:files].empty? && options[:skip_empty] existing_gist = options[:update].to_s.split("/").last url = "#{base_path}/gists" url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != '' request = Net::HTTP::Post.new(url) request['Authorization'] = "token #{access_token}" if access_token.to_s != '' request.body = JSON.dump(json) request.content_type = 'application/json' retried = false begin response = http(api_url, request) if Net::HTTPSuccess === response on_success(response.body, options) else raise "Got #{response.class} from gist: #{response.body}" end rescue => e raise if retried retried = true retry end rescue => e raise e.extend Error end
Called after an HTTP response to gist to perform post-processing.
@param [String] body the text body from the github api @param [Hash] options more detailed options, see
the documentation for {multi_gist}
# File lib/gist.rb, line 437 def on_success(body, options={}) json = JSON.parse(body) output = case options[:output] when :javascript %Q{<script src="#{json['html_url']}.js"></script>} when :html_url json['html_url'] when :raw_url rawify(json['html_url']) when :short_url shorten(json['html_url']) when :short_raw_url shorten(rawify(json['html_url'])) else json end Gist.copy(output.to_s) if options[:copy] Gist.open(json['html_url']) if options[:open] output end
Open a URL in a browser.
@param [String] url @raise [RuntimeError] if no browser integration could be found
This method was heavily inspired by defunkt's Gist#open, @see github.com/defunkt/gist/blob/bca9b29/lib/gist.rb#L157
# File lib/gist.rb, line 530 def open(url) command = if ENV['BROWSER'] ENV['BROWSER'] elsif RUBY_PLATFORM =~ /darwin/ 'open' elsif RUBY_PLATFORM =~ /linux/ %w( sensible-browser xdg-open firefox firefox-bin ).detect do |cmd| which cmd end elsif ENV['OS'] == 'Windows_NT' || RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw|wince/i 'start ""' else raise "Could not work out how to use a browser." end `#{command} #{url}` end
Get a string from the clipboard.
@param [String] content @raise [Gist::Error] if no clipboard integration could be found
# File lib/gist.rb, line 486 def paste `#{clipboard_command(:paste)}` end
return prettified string result of response body for all gists
@params [Net::HTTPResponse] response @return [String] prettified result of listing all gists
see developer.github.com/v3/gists/#response
# File lib/gist.rb, line 286 def pretty_gist(response) body = JSON.parse(response.body) if response.code == '200' body.each do |gist| description = "#{gist['description'] || gist['files'].keys.join(" ")} #{gist['public'] ? '' : '(secret)'}" puts "#{gist['html_url']} #{description.tr("\n", " ")}\n" $stdout.flush end else raise Error, body['message'] end end
Convert github url into raw file url
Unfortunately the url returns from github's api is legacy, we have to taking a HTTPRedirection before appending it with '/raw'. Let's looking forward for github's api fix :)
@param [String] url @return [String] the raw file url
# File lib/gist.rb, line 326 def rawify(url) uri = URI(url) request = Net::HTTP::Get.new(uri.path) response = http(uri, request) if Net::HTTPSuccess === response url + '/raw' elsif Net::HTTPRedirection === response rawify(response.header['location']) end end
# File lib/gist.rb, line 218 def read_gist(id, file_name=nil) url = "#{base_path}/gists/#{id}" access_token = auth_token() request = Net::HTTP::Get.new(url) request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) if response.code == '200' body = JSON.parse(response.body) files = body["files"] if file_name file = files[file_name] raise Error, "Gist with id of #{id} and file #{file_name} does not exist." unless file else file = files.values.first end puts file["content"] else raise Error, "Gist with id of #{id} does not exist." end end
Convert long github urls into short git.io ones
@param [String] url @return [String] shortened url, or long url if shortening fails
# File lib/gist.rb, line 304 def shorten(url) request = Net::HTTP::Post.new("/create") request.set_form_data(:url => url) response = http(GIT_IO_URL, request) case response.code when "200" URI.join(GIT_IO_URL, response.body).to_s when "201" response['Location'] else url end end
# File lib/gist.rb, line 568 def should_be_public?(options={}) if options.key? :private !options[:private] else !Gist.legacy_private_gister? end end
Find command from PATH environment.
@param [String] cmd command name to find @param [String] options PATH environment variable @return [String] the command found
# File lib/gist.rb, line 495 def which(cmd, path=ENV['PATH']) if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin|cygwin/ path.split(File::PATH_SEPARATOR).each {|dir| f = File.join(dir, cmd+".exe") return f if File.executable?(f) && !File.directory?(f) } nil else return system("which #{cmd} > /dev/null 2>&1") end end