class Net::Gemini
A Gemini
client API for Ruby.¶ ↑
Net::Gemini
provides a rich library which can be used to build Gemini
user-agents. @see gemini.circumlunar.space/docs/specification.html
Net::Gemini
is designed to work closely with URI
.
Simple Examples¶ ↑
All examples assume you have loaded Net::Gemini
with:
require 'net/gemini'
This will also require 'uri' so you don't need to require it separately.
The Net::Gemini
methods in the following section do not persist connections.
GET by URI
¶ ↑
uri = URI('gemini://gemini.circumlunar.space/') Net::Gemini.get(uri) # => String
GET with Dynamic Parameters¶ ↑
uri = URI('gemini://gus.guru/search') uri.query = URI.encode_www_form('test') res = Net::Gemini.get_response(uri) puts res.body if res.body_permitted?
Response Data¶ ↑
res = Net::Gemini.get_response(URI('gemini://gemini.circumlunar.space/')) # Status puts res.status # => '20' puts res.meta # => 'text/gemini; charset=UTF-8; lang=en' # Headers puts res.header.inspect # => { status: '20', meta: 'text/gemini; charset=UTF-8', mimetype: 'text/gemini', lang: 'en', charset: 'utf-8', format: nil }
The lang, charset and format headers will only be provided in case of `text/*` mimetype, and only if body for 2* status codes.
# Body puts res.body if res.body_permitted? puts res.body(flowed: 85)
Following Redirection¶ ↑
The {#fetch} method, contrary to the {#request} one will try to automatically resolves redirection, leading you to the final destination.
u = URI('gemini://exemple.com/redirect') res = Net::Gemini.start(u.host, u.port) do |g| g.request(u) end puts "#{res.status} - #{res.meta}" # => '30 final/dest' puts res.uri.to_s # => 'gemini://exemple.com/redirect' u = URI('gemini://exemple.com/redirect') res = Net::Gemini.start(u.host, u.port) do |g| g.fetch(u) end puts "#{res.status} - #{res.meta}" # => '20 - text/gemini;' puts res.uri.to_s # => 'gemini://exemple.com/final/dest'
Attributes
certs_path[W]
Public Class Methods
get(uri)
click to toggle source
# File lib/net/gemini.rb, line 149 def get(uri) get_response(uri).body end
get_response(uri)
click to toggle source
# File lib/net/gemini.rb, line 145 def get_response(uri) start(uri.host, uri.port) { |gem| gem.fetch(uri) } end
new(host, port)
click to toggle source
# File lib/net/gemini.rb, line 94 def initialize(host, port) @host = host @port = port @certs_path = '~/.cache/gemini/certs' end
start(host_or_uri, port = nil) { |gem| ... }
click to toggle source
# File lib/net/gemini.rb, line 133 def start(host_or_uri, port = nil) if host_or_uri.is_a? URI::Gemini host = host_or_uri.host port = host_or_uri.port else host = host_or_uri end gem = new(host, port) return yield(gem) if block_given? gem end
Public Instance Methods
fetch(uri, limit = 5)
click to toggle source
# File lib/net/gemini.rb, line 119 def fetch(uri, limit = 5) raise GeminiError, 'Too many Gemini redirects' if limit.zero? r = request(uri) return r unless r.status[0] == '3' begin uri = handle_redirect(r) rescue ArgumentError, URI::InvalidURIError return r end warn "Redirect to #{uri}" if $VERBOSE fetch(uri, limit - 1) end
request(uri)
click to toggle source
# File lib/net/gemini.rb, line 100 def request(uri) init_sockets req = GeminiRequest.new uri req.write @ssl_socket res = GeminiResponse.read_new(@ssl_socket) res.uri = uri res.reading_body(@ssl_socket) rescue OpenSSL::SSL::SSLError => e msg = format( 'SSLError: %<cause>s', cause: e.message.sub(/.*state=error: (.+)\Z/, '\1') ) GeminiResponse.new('59', msg) ensure # Stop remaining connection, even if they should be already cut # by the server finish end
Private Instance Methods
handle_redirect(response)
click to toggle source
# File lib/net/gemini.rb, line 156 def handle_redirect(response) uri = response.uri old_url = uri.to_s new_uri = URI(response.meta) uri.merge!(new_uri) raise GeminiError, "Redirect loop on #{uri}" if uri.to_s == old_url @host = uri.host @port = uri.port uri end