discodactyl 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -6
- data/MANIFEST +9 -1
- data/{README → README.rdoc} +19 -5
- data/TODO +22 -5
- data/bin/webfinger +59 -14
- data/discodactyl.gemspec +7 -5
- data/lib/discodactyl/acct_uri.rb +3 -1
- data/lib/discodactyl/host_meta.rb +12 -0
- data/lib/discodactyl/host_meta_jrd.rb +35 -0
- data/lib/discodactyl/jrd/document.rb +49 -0
- data/lib/discodactyl/jrd/link.rb +25 -0
- data/lib/discodactyl/jrd.rb +2 -0
- data/lib/discodactyl/known_rels.rb +12 -0
- data/lib/discodactyl/link_header.rb +2 -2
- data/lib/discodactyl/log.rb +5 -0
- data/lib/discodactyl/resource_discovery.rb +22 -1
- data/lib/discodactyl/xrd/document.rb +15 -1
- data/lib/discodactyl/xrd/link.rb +5 -6
- data/lib/discodactyl.rb +5 -1
- data/test/test_host_meta_jrd.rb +63 -0
- data/test/test_jrd_document.rb +142 -0
- metadata +70 -15
    
        data/Gemfile
    CHANGED
    
    
    
        data/MANIFEST
    CHANGED
    
    | @@ -5,7 +5,7 @@ Gemfile | |
| 5 5 | 
             
            INSTALL
         | 
| 6 6 | 
             
            MANIFEST
         | 
| 7 7 | 
             
            NEWS
         | 
| 8 | 
            -
            README
         | 
| 8 | 
            +
            README.rdoc
         | 
| 9 9 | 
             
            Rakefile
         | 
| 10 10 | 
             
            TODO
         | 
| 11 11 | 
             
            bin/webfinger
         | 
| @@ -13,7 +13,13 @@ discodactyl.gemspec | |
| 13 13 | 
             
            lib/discodactyl.rb
         | 
| 14 14 | 
             
            lib/discodactyl/acct_uri.rb
         | 
| 15 15 | 
             
            lib/discodactyl/host_meta.rb
         | 
| 16 | 
            +
            lib/discodactyl/host_meta_jrd.rb
         | 
| 17 | 
            +
            lib/discodactyl/jrd.rb
         | 
| 18 | 
            +
            lib/discodactyl/jrd/document.rb
         | 
| 19 | 
            +
            lib/discodactyl/jrd/link.rb
         | 
| 20 | 
            +
            lib/discodactyl/known_rels.rb
         | 
| 16 21 | 
             
            lib/discodactyl/link_header.rb
         | 
| 22 | 
            +
            lib/discodactyl/log.rb
         | 
| 17 23 | 
             
            lib/discodactyl/resource_discovery.rb
         | 
| 18 24 | 
             
            lib/discodactyl/uri_template.rb
         | 
| 19 25 | 
             
            lib/discodactyl/xrd.rb
         | 
| @@ -22,6 +28,8 @@ lib/discodactyl/xrd/link.rb | |
| 22 28 | 
             
            test/test_acct_uri.rb
         | 
| 23 29 | 
             
            test/test_helper.rb
         | 
| 24 30 | 
             
            test/test_host_meta.rb
         | 
| 31 | 
            +
            test/test_host_meta_jrd.rb
         | 
| 32 | 
            +
            test/test_jrd_document.rb
         | 
| 25 33 | 
             
            test/test_link_header.rb
         | 
| 26 34 | 
             
            test/test_resource_discovery.rb
         | 
| 27 35 | 
             
            test/test_uri_template.rb
         | 
    
        data/{README → README.rdoc}
    RENAMED
    
    | @@ -1,9 +1,10 @@ | |
| 1 1 | 
             
            = Discodactyl
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 3 | 
            +
            Code :: http://github.com/josephholsten/discodactyl
         | 
| 4 | 
            +
            Bugs :: http://josephholsten.lighthouseapp.com/projects/36040-discodactyl
         | 
| 5 | 
            +
            Tests :: http://discodactyl-ci.heroku.com/
         | 
| 6 | 
            +
            Docs :: http://rdoc.info/projects/josephholsten/discodactyl
         | 
| 7 | 
            +
            Author :: mailto:joseph@josephholsten.com
         | 
| 7 8 |  | 
| 8 9 | 
             
            == DESCRIPTION:
         | 
| 9 10 |  | 
| @@ -18,9 +19,22 @@ Discodactyl is an experimental toolkit for XRD service discovery documents and r | |
| 18 19 | 
             
            * acct: URI parsing.
         | 
| 19 20 | 
             
            * Minimal URI Template parsing and application.
         | 
| 20 21 | 
             
            * Probably filled with bugs. Don't forget your bug powder.
         | 
| 22 | 
            +
            * JRD parsing, querying.
         | 
| 23 | 
            +
            * Yahoo 'webfinger' doesn't work. Sadly, they need to update their format to the most recent one.
         | 
| 21 24 |  | 
| 22 25 | 
             
            == SYNOPSIS:
         | 
| 23 26 |  | 
| 27 | 
            +
            For command-line fiends:
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              $ webfinger bradfitz@gmail.com
         | 
| 30 | 
            +
              Profile: http://www.google.com/profiles/bradfitz
         | 
| 31 | 
            +
              Profile data: http://www-opensocial.googleusercontent.com/api/people/115863474911002159675/
         | 
| 32 | 
            +
              describedby: http://www.google.com/profiles/bradfitz
         | 
| 33 | 
            +
              Contacts: http://www-opensocial.googleusercontent.com/api/people/
         | 
| 34 | 
            +
              Status: Hah... about 4 hours ago
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            For ruby mongers:
         | 
| 37 | 
            +
             | 
| 24 38 | 
             
              # All of WebFinger! In very few, if long and pointy, lines!
         | 
| 25 39 | 
             
              require 'discodactyl'
         | 
| 26 40 |  | 
| @@ -46,7 +60,7 @@ This software is also available in a permissive license. Please contact Joseph H | |
| 46 60 |  | 
| 47 61 | 
             
            (The GNU Affero General Public License)
         | 
| 48 62 |  | 
| 49 | 
            -
            Copyright (c) 2009, 2010 Joseph Anthony Pasquale Holsten
         | 
| 63 | 
            +
            Copyright (c) 2009, 2010, 2011 Joseph Anthony Pasquale Holsten
         | 
| 50 64 |  | 
| 51 65 | 
             
            This program is free software: you can redistribute it and/or modify
         | 
| 52 66 | 
             
            it under the terms of the GNU Affero General Public License as published by
         | 
    
        data/TODO
    CHANGED
    
    | @@ -14,11 +14,28 @@ | |
| 14 14 | 
             
            * REXML support
         | 
| 15 15 | 
             
            * collect common rel values into a enum module
         | 
| 16 16 | 
             
            * put license info in every file
         | 
| 17 | 
            +
            * find out if ruby has a default debug flag
         | 
| 18 | 
            +
            * find well known uris via WellKnown.find(uri, :host_meta)
         | 
| 17 19 |  | 
| 18 20 | 
             
            Reference Specs
         | 
| 19 | 
            -
            * host meta http://tools.ietf.org/html/draft-hammer-hostmeta- | 
| 21 | 
            +
            * host meta http://tools.ietf.org/html/draft-hammer-hostmeta-13
         | 
| 20 22 | 
             
            * webfinger
         | 
| 21 | 
            -
            * xrd http:// | 
| 22 | 
            -
            * lrdd http://tools.ietf.org/html/draft-hammer-discovery- | 
| 23 | 
            -
            * link header http://tools.ietf.org/html/ | 
| 24 | 
            -
            * versioning-rels http://tools.ietf.org/html/ | 
| 23 | 
            +
            * xrd http://docs.oasis-open.org/xri/xrd/v1.0/xrd-1.0.html
         | 
| 24 | 
            +
            * lrdd http://tools.ietf.org/html/draft-hammer-discovery-06
         | 
| 25 | 
            +
            * link header http://tools.ietf.org/html/rfc5988
         | 
| 26 | 
            +
            * versioning-rels http://tools.ietf.org/html/rfc5829
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            Interesting webfinger variants
         | 
| 29 | 
            +
            * joseph@josephholsten.com
         | 
| 30 | 
            +
            * romeda@gmail.com
         | 
| 31 | 
            +
            * will@willmeyer.com
         | 
| 32 | 
            +
            * dclinton@gmail.com
         | 
| 33 | 
            +
            * bradfitz@gmail.com
         | 
| 34 | 
            +
            * dclinton@yahoo.com
         | 
| 35 | 
            +
            * beestage@yahoo.com
         | 
| 36 | 
            +
            * gffletch@aol.com
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            other clients
         | 
| 39 | 
            +
            * webfingerclient-dclinton.appspot.com/
         | 
| 40 | 
            +
            * webfinger.org/lookup/darron@froese.org
         | 
| 41 | 
            +
            * web.mailana.com/labs/findbyemail/
         | 
    
        data/bin/webfinger
    CHANGED
    
    | @@ -7,14 +7,27 @@ require 'open-uri' | |
| 7 7 | 
             
            require 'action_view'
         | 
| 8 8 | 
             
            require 'mofo'
         | 
| 9 9 | 
             
            require 'feedzirra'
         | 
| 10 | 
            +
            require 'logger'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            log = Logger.new(STDOUT)
         | 
| 13 | 
            +
            Discodactyl.log = log
         | 
| 10 14 |  | 
| 11 15 | 
             
            if ARGV.length == 0
         | 
| 12 16 | 
             
            	puts "Usage: #{__FILE__} user@host"
         | 
| 13 17 | 
             
            	exit 0
         | 
| 14 18 | 
             
            end
         | 
| 15 19 |  | 
| 20 | 
            +
            if ARGV[0].match /^-d/
         | 
| 21 | 
            +
              log.level = Logger::DEBUG
         | 
| 22 | 
            +
              # ARGV.unshift
         | 
| 23 | 
            +
              ARGV.shift
         | 
| 24 | 
            +
            else
         | 
| 25 | 
            +
              log.level = Logger::WARN
         | 
| 26 | 
            +
            end
         | 
| 27 | 
            +
             | 
| 16 28 | 
             
            # parse identifier
         | 
| 17 | 
            -
             | 
| 29 | 
            +
            raw_acct = ARGV[0]
         | 
| 30 | 
            +
            acct = URI::ACCT.parse(raw_acct)
         | 
| 18 31 |  | 
| 19 32 | 
             
            # Perform LRDD discovery on acct with the webfinger relation
         | 
| 20 33 | 
             
            finger_rel = "lrdd"
         | 
| @@ -22,41 +35,73 @@ begin | |
| 22 35 | 
             
              webfinger_uris = Discodactyl::ResourceDiscovery.get_uris_by_rel(acct, finger_rel, 'uri' => acct)
         | 
| 23 36 | 
             
            rescue Discodactyl::HostMetaHTTPError => error
         | 
| 24 37 | 
             
              if error.io.status[1] == 'Not Found'
         | 
| 25 | 
            -
                abort "No host meta webfinger information found at #{error.io.base_uri}"
         | 
| 38 | 
            +
                abort "No host meta webfinger information found at #{error.io.base_uri}. Is the file there?"
         | 
| 26 39 | 
             
              else
         | 
| 27 40 | 
             
                raise
         | 
| 28 41 | 
             
              end
         | 
| 42 | 
            +
            rescue Discodactyl::HostMetaSocketError => error
         | 
| 43 | 
            +
              abort "Could not connect to #{error.host}:#{error.port}. Is your internet connection working?"
         | 
| 29 44 | 
             
            end
         | 
| 30 45 |  | 
| 31 46 | 
             
            abort "URI didn't have any linked webfinger URIs" if webfinger_uris.empty?
         | 
| 32 47 |  | 
| 33 48 | 
             
            # retrieve user disco doc
         | 
| 34 | 
            -
             | 
| 49 | 
            +
            begin
         | 
| 50 | 
            +
              disco_uri = webfinger_uris.first
         | 
| 51 | 
            +
              disco_res = open(disco_uri)
         | 
| 52 | 
            +
            rescue OpenURI::HTTPError
         | 
| 53 | 
            +
              abort "Couldn't open the disco doc at #{disco_uri}. Is your host-meta pointed at the right place?"
         | 
| 54 | 
            +
            end
         | 
| 35 55 |  | 
| 36 56 | 
             
            # parse disco doc
         | 
| 37 | 
            -
             | 
| 57 | 
            +
            begin
         | 
| 58 | 
            +
              disco = Discodactyl::JRD::Document.parse(disco_res)
         | 
| 59 | 
            +
              log.debug "disco doc <#{webfinger_uris.first}>:\n#{disco.inspect}\n"
         | 
| 60 | 
            +
            rescue Discodactyl::JRD::ParseError => e
         | 
| 61 | 
            +
              log.debug "disco doc doesn't seem to be a JRD #{e.message}"
         | 
| 62 | 
            +
              disco_res.rewind
         | 
| 63 | 
            +
              disco = Discodactyl::XRD::Document.parse(disco_res)
         | 
| 64 | 
            +
              log.debug "disco doc <#{webfinger_uris.first}>:\n#{disco}\n"
         | 
| 65 | 
            +
            end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            log.debug "links: #{disco.links.map{|r| [r.rel, r.type, r.href]}.inspect}"
         | 
| 68 | 
            +
            log.debug "rels: #{disco.rels.inspect}"
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            if disco.subject
         | 
| 71 | 
            +
              log.debug "subject: #{disco.subject}"
         | 
| 72 | 
            +
              unless acct.to_s == disco.subject.to_s
         | 
| 73 | 
            +
                abort "Disco doc's subject <#{disco.subject}> doesn't match account we're webfingering <#{acct}>"
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            else
         | 
| 76 | 
            +
              log.warn("Disco doc didn't list a subject. Assuming everything is well.")
         | 
| 77 | 
            +
            end
         | 
| 38 78 |  | 
| 39 79 | 
             
            hcard_uri = disco.uris_by_rel('http://microformats.org/profile/hcard').first
         | 
| 40 | 
            -
            hcard = hCard.find(:first => hcard_uri)
         | 
| 80 | 
            +
            hcard = hCard.find(:first => hcard_uri) rescue
         | 
| 41 81 | 
             
            if hcard
         | 
| 42 82 | 
             
              puts "Name: #{hcard.fn.gsub(/\s+/, ' ')}" if hcard.properties.include?('fn')
         | 
| 43 83 | 
             
              puts "Title: #{hcard.title}" if hcard.properties.include?('title')
         | 
| 44 84 | 
             
              puts "Organization: #{hcard.org}" if hcard.properties.include?('org')
         | 
| 45 85 | 
             
            end
         | 
| 46 86 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
            puts "Profile: #{profile}" if profile
         | 
| 87 | 
            +
            links_with_titles = disco.links.select{|l| l.title.present? }
         | 
| 88 | 
            +
            links_with_titles.each do |link|
         | 
| 89 | 
            +
              puts "#{link.title}: #{link.to_uri}"
         | 
| 90 | 
            +
            end
         | 
| 52 91 |  | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 92 | 
            +
            Discodactyl::KNOWN_RELS.each do |name, rel|
         | 
| 93 | 
            +
              uri = disco.uris_by_rel(rel).first
         | 
| 94 | 
            +
              puts "#{name}: #{uri}" if uri
         | 
| 95 | 
            +
            end
         | 
| 55 96 |  | 
| 56 97 | 
             
            activities = disco.uris_by_rel('http://schemas.google.com/g/2010#updates-from').first
         | 
| 57 98 | 
             
            if activities
         | 
| 58 99 | 
             
              feed = Feedzirra::Feed.fetch_and_parse(activities)
         | 
| 59 100 | 
             
              entry = feed.entries.first
         | 
| 60 | 
            -
               | 
| 61 | 
            -
             | 
| 101 | 
            +
              if entry
         | 
| 102 | 
            +
                include ActionView::Helpers::DateHelper
         | 
| 103 | 
            +
                silence_warnings do
         | 
| 104 | 
            +
                  puts "Status: #{Loofah::Helpers.strip_tags(entry.content)} #{time_ago_in_words(entry.published)} ago"
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              end
         | 
| 62 107 | 
             
            end
         | 
    
        data/discodactyl.gemspec
    CHANGED
    
    | @@ -7,17 +7,19 @@ Gem::Specification.new do |spec| | |
| 7 7 | 
             
              spec.email = "joseph@josephholsten.com"
         | 
| 8 8 | 
             
              spec.homepage = "http://dactylo.us"
         | 
| 9 9 | 
             
              spec.description = %q{Discodactyl is an experimental toolkit for XRD service discovery documents and related protocols. It includes implementations of XRD URITemplate Link-Patterns, basic site-meta support, HTTP Link header parsing, acct: URIs and a webfinger poking stick.}
         | 
| 10 | 
            -
              spec.extra_rdoc_files = %w[ AUTHORS CHANGELOG COPYING INSTALL NEWS README TODO ]
         | 
| 10 | 
            +
              spec.extra_rdoc_files = %w[ AUTHORS CHANGELOG COPYING INSTALL NEWS README.rdoc TODO ]
         | 
| 11 11 | 
             
              spec.rdoc_options << "--charset=UTF-8" <<
         | 
| 12 12 | 
             
                                   "--title" << "Discodactyl Documentation" <<
         | 
| 13 | 
            -
                                   "--main"  << "README"
         | 
| 13 | 
            +
                                   "--main"  << "README.rdoc"
         | 
| 14 14 | 
             
              spec.version = version
         | 
| 15 15 | 
             
              spec.summary = spec.description.split(/\.\s+/).first
         | 
| 16 16 | 
             
              spec.files = File.read("MANIFEST").split(/\r?\n\r?/)
         | 
| 17 17 | 
             
              spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
         | 
| 18 18 | 
             
              spec.test_files = spec.files.grep(/^test\/.*test_.*\.rb$/)
         | 
| 19 | 
            -
              spec.add_runtime_dependency 'nokogiri', '~>1.4. | 
| 20 | 
            -
              spec.add_runtime_dependency 'actionpack', '~> | 
| 19 | 
            +
              spec.add_runtime_dependency 'nokogiri', '~>1.4.2'
         | 
| 20 | 
            +
              spec.add_runtime_dependency 'actionpack', '~>3.0.0'
         | 
| 21 21 | 
             
              spec.add_runtime_dependency 'feedzirra', '~>0.0.23'
         | 
| 22 | 
            -
              spec.add_runtime_dependency 'mofo', '~>0.2. | 
| 22 | 
            +
              spec.add_runtime_dependency 'mofo', '~>0.2.16'
         | 
| 23 | 
            +
              spec.add_development_dependency 'rr', '~>0.10.11'
         | 
| 24 | 
            +
              spec.add_development_dependency 'rake', '~>0.8.7'
         | 
| 23 25 | 
             
            end
         | 
    
        data/lib/discodactyl/acct_uri.rb
    CHANGED
    
    | @@ -13,7 +13,9 @@ module URI # :nodoc: | |
| 13 13 | 
             
                  /^(acct:)?(.*)$/ =~ str
         | 
| 14 14 | 
             
                  scheme = 'acct'
         | 
| 15 15 | 
             
                  opaque = $2
         | 
| 16 | 
            -
                  self.new(scheme, nil, nil, nil, nil, nil, opaque, nil, nil)
         | 
| 16 | 
            +
                  acct = self.new(scheme, nil, nil, nil, nil, nil, opaque, nil, nil)
         | 
| 17 | 
            +
                  Discodactyl.log.debug("Parsed #{str.inspect} into URI #{acct.inspect}") if Discodactyl.log
         | 
| 18 | 
            +
                  acct
         | 
| 17 19 | 
             
                end
         | 
| 18 20 |  | 
| 19 21 |  | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            require 'discodactyl/xrd'
         | 
| 2 2 | 
             
            require 'open-uri'
         | 
| 3 | 
            +
            require 'socket'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module Discodactyl # :nodoc
         | 
| 5 6 | 
             
              # Convienient access to host metadata and individual resources controlled by 
         | 
| @@ -15,6 +16,7 @@ module Discodactyl # :nodoc | |
| 15 16 | 
             
                  # Take a URI and retrieve its HostMeta document
         | 
| 16 17 | 
             
                  def from_uri(uri)
         | 
| 17 18 | 
             
                    uri = get_uri_from_uri(uri)
         | 
| 19 | 
            +
                    Discodactyl.log.debug("got xrd host-meta uri: #{uri}") if Discodactyl.log
         | 
| 18 20 | 
             
                    begin
         | 
| 19 21 | 
             
                      raw = uri.open
         | 
| 20 22 | 
             
                    rescue OpenURI::HTTPError => error
         | 
| @@ -24,6 +26,8 @@ module Discodactyl # :nodoc | |
| 24 26 | 
             
                      else
         | 
| 25 27 | 
             
                        raise
         | 
| 26 28 | 
             
                      end
         | 
| 29 | 
            +
                    rescue ::SocketError => error
         | 
| 30 | 
            +
                      raise HostMetaSocketError.new(error.message, uri.host, uri.port)
         | 
| 27 31 | 
             
                    end
         | 
| 28 32 | 
             
                    self.parse raw
         | 
| 29 33 | 
             
                  end
         | 
| @@ -31,4 +35,12 @@ module Discodactyl # :nodoc | |
| 31 35 | 
             
              end
         | 
| 32 36 | 
             
              class HostMetaHTTPError < OpenURI::HTTPError # :nodoc:
         | 
| 33 37 | 
             
              end
         | 
| 38 | 
            +
              class HostMetaSocketError < StandardError # :nodoc:
         | 
| 39 | 
            +
                attr_accessor :host, :port
         | 
| 40 | 
            +
                def initialize(msg = nil, host = nil, port = nil)
         | 
| 41 | 
            +
                  message = msg
         | 
| 42 | 
            +
                  @host = host
         | 
| 43 | 
            +
                  @port = port
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 34 46 | 
             
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'open-uri'
         | 
| 2 | 
            +
            require 'active_support'
         | 
| 3 | 
            +
            require 'socket'
         | 
| 4 | 
            +
            require "discodactyl/uri_template"
         | 
| 5 | 
            +
            require "discodactyl/jrd"
         | 
| 6 | 
            +
            require 'discodactyl/log'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Discodactyl
         | 
| 9 | 
            +
              class HostMetaJRD < Discodactyl::JRD::Document
         | 
| 10 | 
            +
                # Take a URI and return the URI for its HostMeta document
         | 
| 11 | 
            +
                def self.get_uri_from_uri(uri)
         | 
| 12 | 
            +
                  host = uri.respond_to?('host') ? uri.host : uri
         | 
| 13 | 
            +
                  URI.parse('http://'+ host + '/.well-known/host-meta.json')
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                # Take a URI and retrieve its HostMeta document
         | 
| 17 | 
            +
                def self.from_uri(uri)
         | 
| 18 | 
            +
                  uri = get_uri_from_uri(uri)
         | 
| 19 | 
            +
                  Discodactyl.log.debug("got jrd host-meta uri: #{uri}") if Discodactyl.log
         | 
| 20 | 
            +
                  begin
         | 
| 21 | 
            +
                    raw = uri.open
         | 
| 22 | 
            +
                  rescue OpenURI::HTTPError => error
         | 
| 23 | 
            +
                    if error.io.status[1] == 'Not Found'
         | 
| 24 | 
            +
                      error.io.base_uri = uri
         | 
| 25 | 
            +
                      raise HostMetaHTTPError.new(error.message, error.io)
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      raise
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  rescue ::SocketError => error
         | 
| 30 | 
            +
                    raise HostMetaSocketError.new(error.message, uri.host, uri.port)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                  self.parse raw
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            require 'nokogiri'
         | 
| 2 | 
            +
            require 'active_support'
         | 
| 3 | 
            +
            require 'discodactyl/jrd/link'
         | 
| 4 | 
            +
            require "discodactyl/uri_template"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Discodactyl # :nodoc:
         | 
| 7 | 
            +
            module JRD # :nodoc:
         | 
| 8 | 
            +
              class Document < Hash
         | 
| 9 | 
            +
                def self.parse(raw)
         | 
| 10 | 
            +
                  begin
         | 
| 11 | 
            +
                    Discodactyl.log.debug("parsing jrd: #{raw}") if Discodactyl.log
         | 
| 12 | 
            +
                    decoded = ActiveSupport::JSON.decode(raw)
         | 
| 13 | 
            +
                  rescue => e
         | 
| 14 | 
            +
                    raise ParseError.new(e.message)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  self.[](decoded)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def uris_by_rel(rel, params={})
         | 
| 20 | 
            +
                  links_by_rel(rel).map do |link|
         | 
| 21 | 
            +
                    link.href || link.template.to_uri(params)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                def links_by_rel(rel)
         | 
| 26 | 
            +
                  if self.has_key? 'links' and self['links'].has_key? rel
         | 
| 27 | 
            +
                    self['links'][rel].map{|link| Link.parse(link.merge('rel'=>rel)) }
         | 
| 28 | 
            +
                  else
         | 
| 29 | 
            +
                    []
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                def links
         | 
| 34 | 
            +
                  rels.map do |rel, links|
         | 
| 35 | 
            +
                    links.map {|link| Link.parse(link.merge('rel' => rel)) }
         | 
| 36 | 
            +
                  end.flatten
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def rels
         | 
| 40 | 
            +
                  self['links'] || []
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                def subject
         | 
| 44 | 
            +
                  self['subject']
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              class ParseError < StandardError; end
         | 
| 48 | 
            +
            end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            require 'discodactyl/uri_template'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Discodactyl # :nodoc:
         | 
| 4 | 
            +
            module JRD # :nodoc:
         | 
| 5 | 
            +
              class Link < Struct.new(:href, :template, :rel, :title, :type)
         | 
| 6 | 
            +
                attr_accessor :raw
         | 
| 7 | 
            +
                class << self
         | 
| 8 | 
            +
                  def parse(element)
         | 
| 9 | 
            +
                    self.new.tap do |link|
         | 
| 10 | 
            +
                      begin
         | 
| 11 | 
            +
                        link.rel = element['rel']
         | 
| 12 | 
            +
                        link.type = element['type']
         | 
| 13 | 
            +
                        link.href = element['href']
         | 
| 14 | 
            +
                        link.title = element['title']
         | 
| 15 | 
            +
                        link.template = URITemplate.new(element['template']) unless link.href
         | 
| 16 | 
            +
                        link.raw = element
         | 
| 17 | 
            +
                      rescue
         | 
| 18 | 
            +
                        raise "Couldn't parse #{link} into a JRD Link"
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            module Discodactyl # :nodoc:
         | 
| 2 | 
            +
              KNOWN_RELS = {
         | 
| 3 | 
            +
                'OpenID' => 'http://specs.openid.net/auth/',
         | 
| 4 | 
            +
                'OpenID Provider' => 'http://specs.openid.net/auth/2.0/provider',
         | 
| 5 | 
            +
                'OpenID Provider' => 'openid2.provider',
         | 
| 6 | 
            +
                "Profile" => 'http://webfinger.net/rel/profile-page',
         | 
| 7 | 
            +
                "Profile data" => 'http://portablecontacts.net/spec/1.0#me',
         | 
| 8 | 
            +
                "Contacts" => 'http://portablecontacts.net/spec/1.0',
         | 
| 9 | 
            +
                "describedby" => 'describedby', # from POWDER
         | 
| 10 | 
            +
                "Webfinger/LRDD" => 'lrdd'
         | 
| 11 | 
            +
              }
         | 
| 12 | 
            +
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            require 'active_support/core_ext/object/misc'
         | 
| 1 | 
            +
            # require 'active_support/core_ext/object/misc'
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Discodactyl # :nodoc:
         | 
| 4 4 | 
             
              # Access to web links stored in HTTP Link header-fields. See also: 
         | 
| @@ -14,7 +14,7 @@ module Discodactyl # :nodoc: | |
| 14 14 | 
             
                  #   link[:href] # '/'
         | 
| 15 15 | 
             
                  #   link[:rel] # ['http://example.net/foo']
         | 
| 16 16 | 
             
                  def parse(string)
         | 
| 17 | 
            -
                     | 
| 17 | 
            +
                    LinkHeader.new.tap do |params|
         | 
| 18 18 | 
             
                      if string =~ /^<([^>]+)>(.*)$/
         | 
| 19 19 | 
             
                        params[:href] = $1
         | 
| 20 20 | 
             
                        $2.split(/;\s*/).each do |part|
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require 'open-uri'
         | 
| 2 2 | 
             
            require 'nokogiri'
         | 
| 3 3 | 
             
            require 'discodactyl/link_header'
         | 
| 4 | 
            +
            require 'discodactyl/log'
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Discodactyl # :nodoc:
         | 
| 6 7 | 
             
              class ResourceDiscovery
         | 
| @@ -20,6 +21,7 @@ module Discodactyl # :nodoc: | |
| 20 21 | 
             
                  def get_uris_by_rel(uri, rel, params = {})
         | 
| 21 22 | 
             
                    begin
         | 
| 22 23 | 
             
                      uri = URI.parse(uri.to_s) unless uri.respond_to?('open')
         | 
| 24 | 
            +
                      Discodactyl.log.debug "Getting uris for uri #{uri.inspect} by rel #{rel.inspect} with params #{params.inspect}" if Discodactyl.log
         | 
| 23 25 | 
             
                      resource = uri.open
         | 
| 24 26 | 
             
                    rescue OpenURI::HTTPError => e
         | 
| 25 27 | 
             
                      status = e.io.status[0] # => 3xx, 4xx, or 5xx
         | 
| @@ -61,9 +63,28 @@ module Discodactyl # :nodoc: | |
| 61 63 | 
             
                      end
         | 
| 62 64 | 
             
                    end
         | 
| 63 65 | 
             
                    unless uris
         | 
| 64 | 
            -
                       | 
| 66 | 
            +
                      Discodactyl.log.debug("getting jrd host-meta") if Discodactyl.log
         | 
| 67 | 
            +
                      begin
         | 
| 68 | 
            +
                        host_meta = Discodactyl::HostMetaJRD.from_uri uri
         | 
| 69 | 
            +
                      rescue => error
         | 
| 70 | 
            +
                        Discodactyl.log.debug("Error parsing jrd host-meta: #{error}") if Discodactyl.log
         | 
| 71 | 
            +
                      end
         | 
| 72 | 
            +
                      Discodactyl.log.debug("finding uris in jrd host-meta") if Discodactyl.log
         | 
| 73 | 
            +
                      uris = host_meta.uris_by_rel(rel, params) if host_meta
         | 
| 74 | 
            +
                    end
         | 
| 75 | 
            +
                    
         | 
| 76 | 
            +
                    unless uris
         | 
| 77 | 
            +
                      Discodactyl.log.debug("Getting xrd host-meta") if Discodactyl.log
         | 
| 78 | 
            +
                      begin
         | 
| 79 | 
            +
                        host_meta = Discodactyl::HostMeta.from_uri uri
         | 
| 80 | 
            +
                      rescue => error
         | 
| 81 | 
            +
                        Discodactyl.log.debug("Error getting xrd host-meta: #{error}") if Discodactyl.log
         | 
| 82 | 
            +
                        raise
         | 
| 83 | 
            +
                      end
         | 
| 84 | 
            +
                      Discodactyl.log.debug("finding uris in host-meta") if Discodactyl.log
         | 
| 65 85 | 
             
                      uris = host_meta.uris_by_rel(rel, params)
         | 
| 66 86 | 
             
                    end
         | 
| 87 | 
            +
                    Discodactyl.log.debug "URIs: #{uris.inspect}" if Discodactyl.log
         | 
| 67 88 | 
             
                    uris
         | 
| 68 89 | 
             
                  end
         | 
| 69 90 |  | 
| @@ -8,6 +8,7 @@ module XRD # :nodoc: | |
| 8 8 | 
             
                class << self
         | 
| 9 9 | 
             
                  def parse(string)
         | 
| 10 10 | 
             
                    raw = Nokogiri::XML(string)
         | 
| 11 | 
            +
                    Discodactyl.log.debug("parsing xrd: #{raw}") if Discodactyl.log
         | 
| 11 12 | 
             
                    doc = self.new
         | 
| 12 13 |  | 
| 13 14 | 
             
                    doc.raw = raw
         | 
| @@ -29,7 +30,8 @@ module XRD # :nodoc: | |
| 29 30 | 
             
                end
         | 
| 30 31 |  | 
| 31 32 | 
             
                def links_by_rel(rel)
         | 
| 32 | 
            -
                  linkelems_by_rel(rel).map {|e| Link.parse(e) }
         | 
| 33 | 
            +
                  # linkelems_by_rel(rel).map {|e| Link.parse(e) }
         | 
| 34 | 
            +
                  find_all_links_by_rel(rel)
         | 
| 33 35 | 
             
                end
         | 
| 34 36 |  | 
| 35 37 | 
             
                def uris_by_rel(rel, params = {})
         | 
| @@ -54,6 +56,10 @@ module XRD # :nodoc: | |
| 54 56 | 
             
                def find_link_by_id(link_id)
         | 
| 55 57 | 
             
                    links.find {|link| link.id == link_id}
         | 
| 56 58 | 
             
                end
         | 
| 59 | 
            +
                
         | 
| 60 | 
            +
                def find_all_links_by_rel(rel)
         | 
| 61 | 
            +
                    links.find_all {|link| link.rel == rel }
         | 
| 62 | 
            +
                end
         | 
| 57 63 |  | 
| 58 64 | 
             
                def ids
         | 
| 59 65 | 
             
                  links.map(&:id).reject(&:nil?)
         | 
| @@ -62,6 +68,10 @@ module XRD # :nodoc: | |
| 62 68 | 
             
                def to_s
         | 
| 63 69 | 
             
                  raw.to_s
         | 
| 64 70 | 
             
                end
         | 
| 71 | 
            +
                
         | 
| 72 | 
            +
                def rels
         | 
| 73 | 
            +
                  links.map(&:rel).reject(&:nil?).uniq
         | 
| 74 | 
            +
                end
         | 
| 65 75 |  | 
| 66 76 | 
             
                def generate_tag_uri
         | 
| 67 77 | 
             
                  scheme = 'tag'
         | 
| @@ -70,6 +80,10 @@ module XRD # :nodoc: | |
| 70 80 | 
             
                  specific = "/xrd/link/#{rand(2**10)}"
         | 
| 71 81 | 
             
                  "#{scheme}:#{authority},#{date}:#{specific}"
         | 
| 72 82 | 
             
                end
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                def subject
         | 
| 85 | 
            +
                  raw.xpath('/xrd:XRD/xrd:Subject', XMLNS).text
         | 
| 86 | 
            +
                end
         | 
| 73 87 | 
             
              end
         | 
| 74 88 | 
             
            end
         | 
| 75 89 | 
             
            end
         | 
    
        data/lib/discodactyl/xrd/link.rb
    CHANGED
    
    | @@ -1,26 +1,25 @@ | |
| 1 1 | 
             
            require 'nokogiri'
         | 
| 2 | 
            -
            require 'active_support/core_ext/object/misc'
         | 
| 3 2 | 
             
            require 'discodactyl/uri_template'
         | 
| 4 3 |  | 
| 5 4 | 
             
            module Discodactyl # :nodoc:
         | 
| 6 5 | 
             
            module XRD # :nodoc:
         | 
| 7 | 
            -
              class Link
         | 
| 6 | 
            +
              class Link < Struct.new(:href, :template, :rel, :title, :type)
         | 
| 7 | 
            +
                attr_accessor :raw
         | 
| 8 8 | 
             
                class << self
         | 
| 9 9 | 
             
                  def parse(element)
         | 
| 10 | 
            -
                     | 
| 10 | 
            +
                    self.new.tap do |link|
         | 
| 11 11 | 
             
                      link.rel = element['rel']
         | 
| 12 12 | 
             
                      link.type = element['type']
         | 
| 13 13 | 
             
                      link.href = element['href']
         | 
| 14 | 
            +
                      link.title = element['title']
         | 
| 14 15 | 
             
                      link.template = URITemplate.new(element['template']) unless link.href
         | 
| 15 16 | 
             
                      link.raw = element
         | 
| 16 17 | 
             
                    end
         | 
| 17 18 | 
             
                  end
         | 
| 18 19 | 
             
                end
         | 
| 19 20 |  | 
| 20 | 
            -
                attr_accessor :href, :template, :rel, :type, :raw
         | 
| 21 | 
            -
             | 
| 22 21 | 
             
                def to_uri(params = {})
         | 
| 23 | 
            -
                   | 
| 22 | 
            +
                  href || template.to_uri(params)
         | 
| 24 23 | 
             
                end
         | 
| 25 24 |  | 
| 26 25 | 
             
                def id
         | 
    
        data/lib/discodactyl.rb
    CHANGED
    
    | @@ -1,9 +1,13 @@ | |
| 1 1 | 
             
            require 'discodactyl/acct_uri'
         | 
| 2 2 | 
             
            require 'discodactyl/host_meta'
         | 
| 3 | 
            +
            require 'discodactyl/host_meta_jrd'
         | 
| 4 | 
            +
            require 'discodactyl/jrd'
         | 
| 5 | 
            +
            require 'discodactyl/known_rels'
         | 
| 6 | 
            +
            require 'discodactyl/log'
         | 
| 3 7 | 
             
            require 'discodactyl/resource_discovery'
         | 
| 4 8 | 
             
            require 'discodactyl/uri_template'
         | 
| 5 9 | 
             
            require 'discodactyl/xrd'
         | 
| 6 10 |  | 
| 7 11 | 
             
            module Discodactyl # :nodoc:
         | 
| 8 | 
            -
              VERSION = '0. | 
| 12 | 
            +
              VERSION = '0.4.1'
         | 
| 9 13 | 
             
            end
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby -w
         | 
| 2 | 
            +
            libdir = File.expand_path('../../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "test/unit"
         | 
| 6 | 
            +
            require "discodactyl/host_meta_jrd"
         | 
| 7 | 
            +
            require 'discodactyl/acct_uri'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            class TestHostMetaJRD < Test::Unit::TestCase
         | 
| 10 | 
            +
              def test_get_uri_from_host
         | 
| 11 | 
            +
                uri = 'host.example'
         | 
| 12 | 
            +
                expected = URI.parse 'http://host.example/.well-known/host-meta.json'
         | 
| 13 | 
            +
                assert_equal expected, Discodactyl::HostMetaJRD.get_uri_from_uri(uri)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def test_get_uri_from_http
         | 
| 17 | 
            +
                uri = URI.parse 'http://host.example/some/path'
         | 
| 18 | 
            +
                expected = URI.parse 'http://host.example/.well-known/host-meta.json'
         | 
| 19 | 
            +
                assert_equal expected, Discodactyl::HostMetaJRD.get_uri_from_uri(uri)
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_get_uri_from_acct
         | 
| 23 | 
            +
                uri = URI.parse 'acct:user@host.example'
         | 
| 24 | 
            +
                expected = URI.parse 'http://host.example/.well-known/host-meta.json'
         | 
| 25 | 
            +
                assert_equal expected, Discodactyl::HostMetaJRD.get_uri_from_uri(uri)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
              def test_from_uri
         | 
| 29 | 
            +
                uri = URI.parse 'acct:josephholsten@localhost'
         | 
| 30 | 
            +
                assert_equal({"links"=>{"lrdd"=>[{"href"=>"http://localhost/discovery.jrd"}]}}, Discodactyl::HostMetaJRD.from_uri(uri))
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def test_parse
         | 
| 34 | 
            +
                json = <<JSON
         | 
| 35 | 
            +
            { "links": {
         | 
| 36 | 
            +
                "lrdd": [{
         | 
| 37 | 
            +
                  "href":"http://host.example/discovery.jrd" }]}}
         | 
| 38 | 
            +
            JSON
         | 
| 39 | 
            +
                assert_equal({"links"=>{"lrdd"=>[{"href"=>"http://host.example/discovery.jrd"}]}}, Discodactyl::HostMetaJRD.parse(json))
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              def test_links_by_rel
         | 
| 43 | 
            +
                jrd = Discodactyl::HostMetaJRD[{"links"=>{"lrdd"=>[{"href"=>"http://host.example/discovery.jrd"}]}}]
         | 
| 44 | 
            +
                expected = [Discodactyl::JRD::Link.parse({'href'=>'http://host.example/discovery.jrd', 'rel' => 'lrdd'})]
         | 
| 45 | 
            +
                assert_equal(expected, jrd.links_by_rel('lrdd'))
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              # links by rel when links is missing, when rel is missing
         | 
| 49 | 
            +
              def test_links_by_rel_when_missing
         | 
| 50 | 
            +
                jrd = Discodactyl::HostMetaJRD[{}]
         | 
| 51 | 
            +
                assert_equal([], jrd.links_by_rel('lrdd'))
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def test_uris_by_rel
         | 
| 55 | 
            +
                jrd = Discodactyl::HostMetaJRD[{"links"=>{"lrdd"=>[{"href"=>"http://host.example/discovery.jrd"}]}}]
         | 
| 56 | 
            +
                assert_equal(['http://host.example/discovery.jrd'], jrd.uris_by_rel('lrdd'))
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def test_uris_by_rel_with_template
         | 
| 60 | 
            +
                jrd = Discodactyl::HostMetaJRD[{"links"=>{"lrdd"=>[{"template"=>"http://host.example/{id}"}]}}]
         | 
| 61 | 
            +
                assert_equal(['http://host.example/foo'], jrd.uris_by_rel('lrdd', 'id' => 'foo'))
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| @@ -0,0 +1,142 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby -w
         | 
| 2 | 
            +
            libdir = File.expand_path('../../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
         | 
| 4 | 
            +
            testdir = File.expand_path('../../test', __FILE__)
         | 
| 5 | 
            +
            $LOAD_PATH.unshift(testdir) unless $LOAD_PATH.include?(testdir)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require 'test_helper'
         | 
| 8 | 
            +
            require 'discodactyl/jrd/document'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            class TestJRDParsing < Test::Unit::TestCase
         | 
| 11 | 
            +
              def setup
         | 
| 12 | 
            +
                @minimal_jrd_string =<<eos
         | 
| 13 | 
            +
            {
         | 
| 14 | 
            +
              "subject":"http://host.example/"
         | 
| 15 | 
            +
            }
         | 
| 16 | 
            +
            eos
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #     @full_jrd_string =<<eos
         | 
| 19 | 
            +
            # {"subject":"http://host.example/","links":{"describedby":[{"href":"http://host.example/endpoint"},{"template":"http://host.example/descriptor?q={%id}"}],"webfinger":[{"href":"http://host.example/endpoint"}],"feed":[{"template":"http://host.example/descriptor?q={%id}"}]}}
         | 
| 20 | 
            +
            # eos
         | 
| 21 | 
            +
            # <"{\"subject\":\"http://host.example/\",\"links\":{\"describedby\":[{\"href\":\"http://host.example/endpoint\"},{\"template\":\"http://host.example/descriptor?q={%id}\"}],\"webfinger\":[{\"href\":\"http://host.example/endpoint\"}],\"feed\":[{\"template\":\"http://host.example/descriptor?q={%id}\"}]}}\n"> expected but was
         | 
| 22 | 
            +
            # <"{\"subject\":\"http://host.example/\",\"links\":{\"webfinger\":[{\"href\":\"http://host.example/endpoint\"}],\"describedby\":[{\"href\":\"http://host.example/endpoint\"},{\"template\":\"http://host.example/descriptor?q={%id}\"}],\"feed\":[{\"template\":\"http://host.example/descriptor?q={%id}\"}]}}">.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                @full_jrd_string =<<eos
         | 
| 25 | 
            +
            {"subject":"http://host.example/","links":{"webfinger":[{"href":"http://host.example/endpoint"}],"describedby":[{"href":"http://host.example/endpoint"},{"template":"http://host.example/descriptor?q={%id}"}],"feed":[{"template":"http://host.example/descriptor?q={%id}"}]}}
         | 
| 26 | 
            +
            eos
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                @raw_link_without_id = '<Link rel="http://oexchange.org/spec/0.8/rel/user-target" type="application/xrd+xml" href="http://www.example.com/linkeater/oexchange.xrd"/>'
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                @raw_link_without_id = '{"http://oexchange.org/spec/0.8/rel/user-target":[{"type":"application/xrd+xml", "href":"http://www.example.com/linkeater/oexchange.xrd"}]}'
         | 
| 31 | 
            +
                @raw_link_with_id = '{"http://oexchange.org/spec/0.8/rel/user-target":[{"id":"foo","type":"application/xrd+xml", "href":"http://www.example.com/linkeater/oexchange.xrd"}]}'
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                @jrd = Discodactyl::JRD::Document.parse(@full_jrd_string)
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              def test_parse
         | 
| 36 | 
            +
                doc = Discodactyl::JRD::Document.parse(@full_jrd_string)
         | 
| 37 | 
            +
                assert_not_nil(doc)
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
              def test_parse_links
         | 
| 40 | 
            +
                assert_equal(4, @jrd.links.length)
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              # def test_linkelems_by_rel
         | 
| 44 | 
            +
              #   link_elems = @jrd.linkelems_by_rel 'describedby'
         | 
| 45 | 
            +
              # 
         | 
| 46 | 
            +
              #   assert_length(2, link_elems)
         | 
| 47 | 
            +
              # 
         | 
| 48 | 
            +
              #   assert_equal 'http://host.example/endpoint', link_elems[0]['href']
         | 
| 49 | 
            +
              #   assert_equal 'http://host.example/descriptor?q={%id}', link_elems[1]['template']
         | 
| 50 | 
            +
              # end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              # def test_linkelems_by_rel_with_multiple_rels
         | 
| 53 | 
            +
              #   link_elems = @jrd.linkelems_by_rel 'describedby'
         | 
| 54 | 
            +
              # 
         | 
| 55 | 
            +
              #   assert_length(2, link_elems)
         | 
| 56 | 
            +
              # 
         | 
| 57 | 
            +
              #   assert_equal 'http://host.example/endpoint', link_elems[0]['href']
         | 
| 58 | 
            +
              #   assert_equal 'http://host.example/descriptor?q={%id}', link_elems[1]['template']
         | 
| 59 | 
            +
              # end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def test_uris_by_rel
         | 
| 62 | 
            +
                uris = @jrd.uris_by_rel 'describedby', 'id' => 'bradfitz@gmail.com'
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                assert_length(2, uris)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                assert_equal 'http://host.example/endpoint', uris[0]
         | 
| 67 | 
            +
                assert_equal 'http://host.example/descriptor?q=bradfitz@gmail.com', uris[1]
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def test_links_by_rel
         | 
| 71 | 
            +
                links = @jrd.links_by_rel('feed')
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                assert_length(1, links)
         | 
| 74 | 
            +
                expected = Discodactyl::URITemplate.new('http://host.example/descriptor?q={%id}')
         | 
| 75 | 
            +
                assert_equal(expected, links[0].template)
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def test_uris_by_rel
         | 
| 79 | 
            +
                links = @jrd.uris_by_rel('feed', 'id' => 'dclinton@gmail.com')
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                assert_length(1, links)
         | 
| 82 | 
            +
                assert_include?('http://host.example/descriptor?q=dclinton@gmail.com', links)
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            #   def test_update
         | 
| 86 | 
            +
            #     jrd_str =<<eos
         | 
| 87 | 
            +
            # <?xml version=\"1.0\"?>
         | 
| 88 | 
            +
            # <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
         | 
| 89 | 
            +
            #   <Subject>http://host.example/</Subject>
         | 
| 90 | 
            +
            #   <Link rel="webfinger" href="http://host.example/endpoint"/>
         | 
| 91 | 
            +
            #   <Link rel="describedby" href="http://host.example/endpoint"/>
         | 
| 92 | 
            +
            #   <Link rel="feed" template="http://host.example/descriptor?q={%id}"/>
         | 
| 93 | 
            +
            #   <Link rel="describedby" template="http://host.example/descriptor?q={%id}"/>
         | 
| 94 | 
            +
            #   <Link href="http://www.example.com/linkeater/oexchange.xrd" rel="http://oexchange.org/spec/0.8/rel/user-target" type="application/xrd+xml"/>
         | 
| 95 | 
            +
            #  </XRD>
         | 
| 96 | 
            +
            # eos
         | 
| 97 | 
            +
            #     doc = Discodactyl::JRD::Document.parse jrd_str
         | 
| 98 | 
            +
            #
         | 
| 99 | 
            +
            #     link = "<Link rel='http://oexchange.org/spec/0.8/rel/user-target' type='application/xrd+xml' href='updated' />"
         | 
| 100 | 
            +
            #
         | 
| 101 | 
            +
            #     doc.raw.xpath('//xrd:Link',Discodactyl::XRD::XMLNS).after(link)
         | 
| 102 | 
            +
            #
         | 
| 103 | 
            +
            #     expected =<<eos
         | 
| 104 | 
            +
            # <?xml version=\"1.0\"?>
         | 
| 105 | 
            +
            # <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
         | 
| 106 | 
            +
            #   <Subject>http://host.example/</Subject>
         | 
| 107 | 
            +
            #   <Link rel="webfinger" href="http://host.example/endpoint"/>
         | 
| 108 | 
            +
            #   <Link rel="describedby" href="http://host.example/endpoint"/>
         | 
| 109 | 
            +
            #   <Link rel="feed" template="http://host.example/descriptor?q={%id}"/>
         | 
| 110 | 
            +
            #   <Link rel="describedby" template="http://host.example/descriptor?q={%id}"/>
         | 
| 111 | 
            +
            #   <Link href="updated" rel="http://oexchange.org/spec/0.8/rel/user-target" type="application/xrd+xml"/>
         | 
| 112 | 
            +
            #  </XRD>
         | 
| 113 | 
            +
            # eos
         | 
| 114 | 
            +
            #
         | 
| 115 | 
            +
            #     assert_equal expected, doc.to_s
         | 
| 116 | 
            +
            #   end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            #   def test_delete
         | 
| 119 | 
            +
            #     xrd_str =<<eos
         | 
| 120 | 
            +
            # <?xml version=\"1.0\"?>
         | 
| 121 | 
            +
            # <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
         | 
| 122 | 
            +
            #   <Subject>http://host.example/</Subject>
         | 
| 123 | 
            +
            #   <Link xml:id='1' href="http://example.com/" rel="user-target" type="application/xrd+xml"/>
         | 
| 124 | 
            +
            #  </XRD>
         | 
| 125 | 
            +
            # eos
         | 
| 126 | 
            +
            #     doc = Discodactyl::XRD::Document.parse xrd_str
         | 
| 127 | 
            +
            #
         | 
| 128 | 
            +
            #     link = "<Link rel='http://oexchange.org/spec/0.8/rel/user-target' type='application/xrd+xml' href='updated' />"
         | 
| 129 | 
            +
            #
         | 
| 130 | 
            +
            #     doc.raw.xpath('//xrd:Link',Discodactyl::XRD::XMLNS).after(link)
         | 
| 131 | 
            +
            #
         | 
| 132 | 
            +
            #     expected =<<eos
         | 
| 133 | 
            +
            # <?xml version=\"1.0\"?>
         | 
| 134 | 
            +
            # <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
         | 
| 135 | 
            +
            #   <Subject>http://host.example/</Subject>
         | 
| 136 | 
            +
            #  </XRD>
         | 
| 137 | 
            +
            # eos
         | 
| 138 | 
            +
            #
         | 
| 139 | 
            +
            #     assert_equal expected, doc.to_s
         | 
| 140 | 
            +
            #     assert !doc.include?(link)
         | 
| 141 | 
            +
            #   end
         | 
| 142 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: discodactyl
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              hash: 13
         | 
| 5 | 
            +
              prerelease: 
         | 
| 5 6 | 
             
              segments: 
         | 
| 6 7 | 
             
              - 0
         | 
| 7 | 
            -
              -  | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              version: 0. | 
| 8 | 
            +
              - 4
         | 
| 9 | 
            +
              - 1
         | 
| 10 | 
            +
              version: 0.4.1
         | 
| 10 11 | 
             
            platform: ruby
         | 
| 11 12 | 
             
            authors: 
         | 
| 12 13 | 
             
            - Joseph Anthony Pasquale Holsten
         | 
| @@ -14,44 +15,50 @@ autorequire: | |
| 14 15 | 
             
            bindir: bin
         | 
| 15 16 | 
             
            cert_chain: []
         | 
| 16 17 |  | 
| 17 | 
            -
            date:  | 
| 18 | 
            +
            date: 2011-03-14 00:00:00 -05:00
         | 
| 18 19 | 
             
            default_executable: 
         | 
| 19 20 | 
             
            dependencies: 
         | 
| 20 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 21 22 | 
             
              name: nokogiri
         | 
| 22 23 | 
             
              prerelease: false
         | 
| 23 24 | 
             
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 25 | 
            +
                none: false
         | 
| 24 26 | 
             
                requirements: 
         | 
| 25 27 | 
             
                - - ~>
         | 
| 26 28 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 29 | 
            +
                    hash: 3
         | 
| 27 30 | 
             
                    segments: 
         | 
| 28 31 | 
             
                    - 1
         | 
| 29 32 | 
             
                    - 4
         | 
| 30 | 
            -
                    -  | 
| 31 | 
            -
                    version: 1.4. | 
| 33 | 
            +
                    - 2
         | 
| 34 | 
            +
                    version: 1.4.2
         | 
| 32 35 | 
             
              type: :runtime
         | 
| 33 36 | 
             
              version_requirements: *id001
         | 
| 34 37 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 35 38 | 
             
              name: actionpack
         | 
| 36 39 | 
             
              prerelease: false
         | 
| 37 40 | 
             
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 41 | 
            +
                none: false
         | 
| 38 42 | 
             
                requirements: 
         | 
| 39 43 | 
             
                - - ~>
         | 
| 40 44 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 45 | 
            +
                    hash: 7
         | 
| 41 46 | 
             
                    segments: 
         | 
| 42 | 
            -
                    - 2
         | 
| 43 47 | 
             
                    - 3
         | 
| 44 48 | 
             
                    - 0
         | 
| 45 | 
            -
                     | 
| 49 | 
            +
                    - 0
         | 
| 50 | 
            +
                    version: 3.0.0
         | 
| 46 51 | 
             
              type: :runtime
         | 
| 47 52 | 
             
              version_requirements: *id002
         | 
| 48 53 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 49 54 | 
             
              name: feedzirra
         | 
| 50 55 | 
             
              prerelease: false
         | 
| 51 56 | 
             
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 57 | 
            +
                none: false
         | 
| 52 58 | 
             
                requirements: 
         | 
| 53 59 | 
             
                - - ~>
         | 
| 54 60 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 61 | 
            +
                    hash: 49
         | 
| 55 62 | 
             
                    segments: 
         | 
| 56 63 | 
             
                    - 0
         | 
| 57 64 | 
             
                    - 0
         | 
| @@ -63,16 +70,50 @@ dependencies: | |
| 63 70 | 
             
              name: mofo
         | 
| 64 71 | 
             
              prerelease: false
         | 
| 65 72 | 
             
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 73 | 
            +
                none: false
         | 
| 66 74 | 
             
                requirements: 
         | 
| 67 75 | 
             
                - - ~>
         | 
| 68 76 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 77 | 
            +
                    hash: 55
         | 
| 69 78 | 
             
                    segments: 
         | 
| 70 79 | 
             
                    - 0
         | 
| 71 80 | 
             
                    - 2
         | 
| 72 | 
            -
                    -  | 
| 73 | 
            -
                    version: 0.2. | 
| 81 | 
            +
                    - 16
         | 
| 82 | 
            +
                    version: 0.2.16
         | 
| 74 83 | 
             
              type: :runtime
         | 
| 75 84 | 
             
              version_requirements: *id004
         | 
| 85 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 86 | 
            +
              name: rr
         | 
| 87 | 
            +
              prerelease: false
         | 
| 88 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 89 | 
            +
                none: false
         | 
| 90 | 
            +
                requirements: 
         | 
| 91 | 
            +
                - - ~>
         | 
| 92 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 93 | 
            +
                    hash: 33
         | 
| 94 | 
            +
                    segments: 
         | 
| 95 | 
            +
                    - 0
         | 
| 96 | 
            +
                    - 10
         | 
| 97 | 
            +
                    - 11
         | 
| 98 | 
            +
                    version: 0.10.11
         | 
| 99 | 
            +
              type: :development
         | 
| 100 | 
            +
              version_requirements: *id005
         | 
| 101 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 102 | 
            +
              name: rake
         | 
| 103 | 
            +
              prerelease: false
         | 
| 104 | 
            +
              requirement: &id006 !ruby/object:Gem::Requirement 
         | 
| 105 | 
            +
                none: false
         | 
| 106 | 
            +
                requirements: 
         | 
| 107 | 
            +
                - - ~>
         | 
| 108 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 109 | 
            +
                    hash: 49
         | 
| 110 | 
            +
                    segments: 
         | 
| 111 | 
            +
                    - 0
         | 
| 112 | 
            +
                    - 8
         | 
| 113 | 
            +
                    - 7
         | 
| 114 | 
            +
                    version: 0.8.7
         | 
| 115 | 
            +
              type: :development
         | 
| 116 | 
            +
              version_requirements: *id006
         | 
| 76 117 | 
             
            description: "Discodactyl is an experimental toolkit for XRD service discovery documents and related protocols. It includes implementations of XRD URITemplate Link-Patterns, basic site-meta support, HTTP Link header parsing, acct: URIs and a webfinger poking stick."
         | 
| 77 118 | 
             
            email: joseph@josephholsten.com
         | 
| 78 119 | 
             
            executables: 
         | 
| @@ -85,7 +126,7 @@ extra_rdoc_files: | |
| 85 126 | 
             
            - COPYING
         | 
| 86 127 | 
             
            - INSTALL
         | 
| 87 128 | 
             
            - NEWS
         | 
| 88 | 
            -
            - README
         | 
| 129 | 
            +
            - README.rdoc
         | 
| 89 130 | 
             
            - TODO
         | 
| 90 131 | 
             
            files: 
         | 
| 91 132 | 
             
            - AUTHORS
         | 
| @@ -95,7 +136,7 @@ files: | |
| 95 136 | 
             
            - INSTALL
         | 
| 96 137 | 
             
            - MANIFEST
         | 
| 97 138 | 
             
            - NEWS
         | 
| 98 | 
            -
            - README
         | 
| 139 | 
            +
            - README.rdoc
         | 
| 99 140 | 
             
            - Rakefile
         | 
| 100 141 | 
             
            - TODO
         | 
| 101 142 | 
             
            - bin/webfinger
         | 
| @@ -103,7 +144,13 @@ files: | |
| 103 144 | 
             
            - lib/discodactyl.rb
         | 
| 104 145 | 
             
            - lib/discodactyl/acct_uri.rb
         | 
| 105 146 | 
             
            - lib/discodactyl/host_meta.rb
         | 
| 147 | 
            +
            - lib/discodactyl/host_meta_jrd.rb
         | 
| 148 | 
            +
            - lib/discodactyl/jrd.rb
         | 
| 149 | 
            +
            - lib/discodactyl/jrd/document.rb
         | 
| 150 | 
            +
            - lib/discodactyl/jrd/link.rb
         | 
| 151 | 
            +
            - lib/discodactyl/known_rels.rb
         | 
| 106 152 | 
             
            - lib/discodactyl/link_header.rb
         | 
| 153 | 
            +
            - lib/discodactyl/log.rb
         | 
| 107 154 | 
             
            - lib/discodactyl/resource_discovery.rb
         | 
| 108 155 | 
             
            - lib/discodactyl/uri_template.rb
         | 
| 109 156 | 
             
            - lib/discodactyl/xrd.rb
         | 
| @@ -112,6 +159,8 @@ files: | |
| 112 159 | 
             
            - test/test_acct_uri.rb
         | 
| 113 160 | 
             
            - test/test_helper.rb
         | 
| 114 161 | 
             
            - test/test_host_meta.rb
         | 
| 162 | 
            +
            - test/test_host_meta_jrd.rb
         | 
| 163 | 
            +
            - test/test_jrd_document.rb
         | 
| 115 164 | 
             
            - test/test_link_header.rb
         | 
| 116 165 | 
             
            - test/test_resource_discovery.rb
         | 
| 117 166 | 
             
            - test/test_uri_template.rb
         | 
| @@ -128,27 +177,31 @@ rdoc_options: | |
| 128 177 | 
             
            - --title
         | 
| 129 178 | 
             
            - Discodactyl Documentation
         | 
| 130 179 | 
             
            - --main
         | 
| 131 | 
            -
            - README
         | 
| 180 | 
            +
            - README.rdoc
         | 
| 132 181 | 
             
            require_paths: 
         | 
| 133 182 | 
             
            - lib
         | 
| 134 183 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 184 | 
            +
              none: false
         | 
| 135 185 | 
             
              requirements: 
         | 
| 136 186 | 
             
              - - ">="
         | 
| 137 187 | 
             
                - !ruby/object:Gem::Version 
         | 
| 188 | 
            +
                  hash: 3
         | 
| 138 189 | 
             
                  segments: 
         | 
| 139 190 | 
             
                  - 0
         | 
| 140 191 | 
             
                  version: "0"
         | 
| 141 192 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 193 | 
            +
              none: false
         | 
| 142 194 | 
             
              requirements: 
         | 
| 143 195 | 
             
              - - ">="
         | 
| 144 196 | 
             
                - !ruby/object:Gem::Version 
         | 
| 197 | 
            +
                  hash: 3
         | 
| 145 198 | 
             
                  segments: 
         | 
| 146 199 | 
             
                  - 0
         | 
| 147 200 | 
             
                  version: "0"
         | 
| 148 201 | 
             
            requirements: []
         | 
| 149 202 |  | 
| 150 203 | 
             
            rubyforge_project: 
         | 
| 151 | 
            -
            rubygems_version: 1. | 
| 204 | 
            +
            rubygems_version: 1.5.0
         | 
| 152 205 | 
             
            signing_key: 
         | 
| 153 206 | 
             
            specification_version: 3
         | 
| 154 207 | 
             
            summary: Discodactyl is an experimental toolkit for XRD service discovery documents and related protocols
         | 
| @@ -156,6 +209,8 @@ test_files: | |
| 156 209 | 
             
            - test/test_acct_uri.rb
         | 
| 157 210 | 
             
            - test/test_helper.rb
         | 
| 158 211 | 
             
            - test/test_host_meta.rb
         | 
| 212 | 
            +
            - test/test_host_meta_jrd.rb
         | 
| 213 | 
            +
            - test/test_jrd_document.rb
         | 
| 159 214 | 
             
            - test/test_link_header.rb
         | 
| 160 215 | 
             
            - test/test_resource_discovery.rb
         | 
| 161 216 | 
             
            - test/test_uri_template.rb
         |