ruby-yadis 0.3 → 0.3.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.
@@ -4,13 +4,15 @@ require 'yadis/service'
4
4
  # Class that handles XRDS parsing and XRD Service element extraction.
5
5
 
6
6
  module XRDSUtil
7
-
8
- @@default_namespace = 'xri://$xrd*($v*2.0)'
9
- @@xrds_namespace = {'xrds' => 'xri://$xrds'}
7
+
8
+ @@namespaces = {
9
+ 'xrdsns' => 'xri://$xrds',
10
+ 'xrdns' => 'xri://$xrd*($v*2.0)'
11
+ }
10
12
 
11
13
  def last_xrd(root_element)
12
- REXML::XPath.match(root_element, '/xrds:XRDS/XRD',
13
- @@xrds_namespace)[-1]
14
+ REXML::XPath.match(root_element, '/xrdsns:XRDS/xrdns:XRD',
15
+ @@namespaces)[-1]
14
16
  end
15
17
 
16
18
  end
@@ -22,7 +24,7 @@ class XRDS
22
24
 
23
25
  # Method for producing a valid XRDS object. Accepts an XML
24
26
  # String. Returns an XRDS object on success, or nil on failure.
25
- # Same as calling XRDS.new, but does not rails ArgumentErrors.
27
+ # Same as calling XRDS.new, but does not raise ArgumentErrors.
26
28
  def XRDS.parse(xml)
27
29
  begin
28
30
  return new(xml)
@@ -56,17 +58,14 @@ class XRDS
56
58
  if xml.root.nil?
57
59
  raise ArgumentError, "No document root"
58
60
  end
59
-
60
- xmlns = xml.root.attributes['xmlns']
61
- if xmlns != @@default_namespace
62
- raise ArgumentError, "Unknown XRID version #{xmlns.to_s}"
63
- end
64
61
 
65
62
  xrd = self.last_xrd(xml.root)
66
63
  raise ArgumentError, "No XRD Elements found" if xrd.nil?
67
64
 
68
- @services = {} # keyed by [service_priority, uri_priority]
69
- xrd.elements.each('Service') {|s| _create_services(s)}
65
+ @services = {} # keyed by [service_priority, uri_priority]
66
+ REXML::XPath.each(xrd, 'xrdns:Service', @@namespaces) do |s|
67
+ _create_services(s)
68
+ end
70
69
  end
71
70
 
72
71
 
@@ -98,7 +97,9 @@ class XRDS
98
97
  service.service_types = []
99
98
 
100
99
  service_element.elements.each('Type') do |t|
101
- service.service_types << t.text.strip
100
+ # XXX: If the Type element is empty, should we add an empty element
101
+ # to our list, or none at all?
102
+ service.service_types << t.text.strip unless t.text.nil?
102
103
  end
103
104
 
104
105
  sp = service_element.attributes['priority']
@@ -0,0 +1,42 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <XRDS xmlns="xri://$xrds" xmlns:xrd="xri://$xrd*($v*2.0)">
3
+ <xrd:XRD>
4
+ <xrd:Service priority="1">
5
+ <xrd:Type>http://lid.netmesh.org/minimum-lid/2.0b9</xrd:Type>
6
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
7
+ </xrd:Service>
8
+ <xrd:Service priority="2">
9
+ <xrd:Type>http://lid.netmesh.org/sso/2.0b9</xrd:Type>
10
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
11
+ </xrd:Service>
12
+ <xrd:Service priority="3">
13
+ <xrd:Type>http://lid.netmesh.org/sso/1.0</xrd:Type>
14
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
15
+ </xrd:Service>
16
+ <xrd:Service priority="4">
17
+ <xrd:Type>http://lid.netmesh.org/relying-party/2.0b9</xrd:Type>
18
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
19
+ </xrd:Service>
20
+ <xrd:Service priority="5">
21
+ <xrd:Type>http://lid.netmesh.org/traversal/2.0b9</xrd:Type>
22
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
23
+ </xrd:Service>
24
+ <xrd:Service priority="6">
25
+ <xrd:Type>http://lid.netmesh.org/format-negotiation/2.0b9</xrd:Type>
26
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
27
+ </xrd:Service>
28
+ <xrd:Service priority="7">
29
+ <xrd:Type>http://lid.netmesh.org/post/sender/2.0b9</xrd:Type>
30
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
31
+ </xrd:Service>
32
+ <xrd:Service priority="8">
33
+ <xrd:Type>http://lid.netmesh.org/post/receiver/2.0b9</xrd:Type>
34
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
35
+ </xrd:Service>
36
+ <xrd:Service priority="9">
37
+ <xrd:Type>http://openid.net/signon/1.0</xrd:Type>
38
+ <xrd:URI>http://mylid.net/brianellin</xrd:URI>
39
+ <openid:Delegate xmlns:openid="http://openid.net/xmlns/1.0">http://mylid.net/brianellin</openid:Delegate>
40
+ </xrd:Service>
41
+ </xrd:XRD>
42
+ </XRDS>
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <XRDS ref="xri://=keturn" xmlns="xri://$xrds">
3
+ <XRD xmlns="xri://$xrd*($v*2.0)">
4
+ <Query>*keturn</Query>
5
+ <Status code="100"/>
6
+ <Expires>2006-06-01T18:00:49.000Z</Expires>
7
+ <ProviderID>xri://=</ProviderID>
8
+ <LocalID priority="10">!2397.58EC.8F7D.D097</LocalID>
9
+ <CanonicalID priority="10">=!2397.58EC.8F7D.D097</CanonicalID>
10
+ <Service priority="10">
11
+ <Type/>
12
+ <Type>xri://+i-service*(+forwarding)*($v*1.0)</Type>
13
+ <ProviderID>xri://!!1003</ProviderID>
14
+ <URI priority="10">https://forwarding.godaddy.amsoftsystems.com</URI>
15
+ </Service>
16
+ <Service priority="10">
17
+ <Type>xri://+i-service*(+contact)*($v*1.0)</Type>
18
+ <ProviderID>xri://!!1003</ProviderID>
19
+ <Path>+contact</Path>
20
+ <MediaType/>
21
+ <MediaType>text/html</MediaType>
22
+ <URI priority="10">https://contact.godaddy.amsoftsystems.com</URI>
23
+ </Service>
24
+ <Service priority="10">
25
+ <Type>xri://+i-service*(+authn)*(+saml)*($v*1.0)</Type>
26
+ <ProviderID>xri://!!1003</ProviderID>
27
+ <Path>+login</Path>
28
+ <URI priority="10">https://isso.godaddy.amsoftsystems.com</URI>
29
+ </Service>
30
+ </XRD>
31
+ </XRDS>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xrds:XRDS
3
+ xmlns:xrds="xri://$xrds"
4
+ xmlns:openid="http://openid.net/xmlns/1.0"
5
+ xmlns="xri://$xrd*($v*1.14121)">
6
+ <XRD>
7
+
8
+ <Service priority="0">
9
+ <Type>http://openid.net/signon/1.0</Type>
10
+ <URI>http://www.myopenid.com/server</URI>
11
+ <openid:Delegate>http://brian.myopenid.com/</openid:Delegate>
12
+ </Service>
13
+
14
+ </XRD>
15
+ </xrds:XRDS>
@@ -9,6 +9,12 @@ class XRDSTestCase < Test::Unit::TestCase
9
9
  assert_not_nil(xrds)
10
10
  assert_equal(xrds.services.length, 1)
11
11
  end
12
+
13
+ File.open('data/brianellin.mylid.xrds') do |f|
14
+ xrds = XRDS.new(f.read)
15
+ assert_not_nil(xrds)
16
+ assert_equal(xrds.services.length, 9)
17
+ end
12
18
  end
13
19
 
14
20
  def test_xrds_good_multi
@@ -29,6 +35,22 @@ class XRDSTestCase < Test::Unit::TestCase
29
35
  end
30
36
  end
31
37
 
38
+ # This is like brian.multi, but uses namespaces a little differently.
39
+ def test_xrds_good_namespaces
40
+ File.open('data/proxy-june1.xrds') do |f|
41
+ xrds = XRDS.new(f.read)
42
+ assert_not_nil(xrds)
43
+ assert_equal(3, xrds.services.length)
44
+ end
45
+ end
46
+
47
+ def test_xrds_unknown_xrd_version
48
+ File.open('data/weirdver.xrds') do |f|
49
+ xrds = XRDS.parse(f.read)
50
+ assert_nil(xrds)
51
+ end
52
+ end
53
+
32
54
  def test_xrds_bad
33
55
  assert_nil(XRDS.parse(nil))
34
56
  assert_nil(XRDS.parse(5))
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: ruby-yadis
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.3"
7
- date: 2006-05-10 00:00:00 -07:00
6
+ version: 0.3.1
7
+ date: 2006-06-09 00:00:00 -07:00
8
8
  summary: A library for performing Yadis service discovery
9
9
  require_paths:
10
10
  - lib
@@ -31,19 +31,13 @@ files:
31
31
  - examples/openid.rb
32
32
  - lib/yadis.rb
33
33
  - lib/yadis
34
- - lib/yadis.rb~
35
34
  - lib/yadis/parsehtml.rb
36
35
  - lib/yadis/xrds.rb
37
36
  - lib/yadis/yadis.rb
38
37
  - lib/yadis/fetcher.rb
39
38
  - lib/yadis/htmltokenizer.rb
40
39
  - lib/yadis/manager.rb
41
- - lib/yadis/yadis.rb~
42
40
  - lib/yadis/service.rb
43
- - lib/yadis/manager.rb~
44
- - lib/yadis/service.rb~
45
- - lib/yadis/xrds.rb~
46
- - lib/yadis/fetcher.rb~
47
41
  - test/test_parse.rb
48
42
  - test/data
49
43
  - test/test_discovery.rb
@@ -52,12 +46,15 @@ files:
52
46
  - test/runtests.rb
53
47
  - test/data/manifest.txt
54
48
  - test/data/brian.xrds
55
- - test/data/index.html
56
- - test/data/brian.multi.xrds
57
49
  - test/data/brian_priority.xrds
50
+ - test/data/brian.multi.xrds
51
+ - test/data/index.html
58
52
  - test/data/brian.multi_uri.xrds
59
- - test/data/index_xrds.html
60
53
  - test/data/index_yadis.html
54
+ - test/data/index_xrds.html
55
+ - test/data/proxy-june1.xrds
56
+ - test/data/weirdver.xrds
57
+ - test/data/brianellin.mylid.xrds
61
58
  - README
62
59
  - INSTALL
63
60
  - COPYING
@@ -1 +0,0 @@
1
- require 'yadis/yadis'
@@ -1,79 +0,0 @@
1
- require "uri"
2
-
3
- begin
4
- require "net/https"
5
- rescue LoadError
6
- HAS_OPENSSL_ = false
7
- require 'net/http'
8
- else
9
- HAS_OPENSSL_ = true
10
- end
11
-
12
- class NetHTTPFetcher
13
-
14
- attr_accessor :ca_path
15
-
16
- def initialize(read_timeout=20, open_timeout=20)
17
- @read_timeout = read_timeout
18
- @open_timeout = open_timeout
19
- @ca_path = nil
20
- end
21
-
22
- def get(url, params = nil)
23
- resp, final_url = do_get(url, params)
24
- if resp.nil?
25
- nil
26
- else
27
- [final_url, resp]
28
- end
29
- end
30
-
31
- protected
32
-
33
- # return a Net::HTTP object ready for use
34
- def get_http_obj(uri)
35
- http = Net::HTTP.new(uri.host, uri.port)
36
- http.read_timeout = @read_timeout
37
- http.open_timeout = @open_timeout
38
-
39
- if uri.scheme == 'https'
40
- if HAS_OPENSSL_
41
- http.use_ssl = true
42
- if @ca_path
43
- http.ca_file = @ca_path
44
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
45
- else
46
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
47
- STDERR.puts("Warning: fetching over https without verifying server certificate")
48
- end
49
- else
50
- STDERR.puts('Warning: trying to fetch HTTPS URL without OpenSSL support')
51
- end
52
- end
53
-
54
- return http
55
- end
56
-
57
- # do a GET following redirects limit deep
58
- def do_get(url, params, limit=5)
59
- if limit == 0
60
- return nil
61
- end
62
- begin
63
- uri = URI.parse(url)
64
- http = get_http_obj(uri)
65
- resp = http.request_get(uri.request_uri, params)
66
- rescue
67
- nil
68
- else
69
- case resp
70
- when Net::HTTPSuccess then [resp, URI.parse(url).to_s]
71
- when Net::HTTPRedirection then do_get(resp["location"], params, limit-1)
72
- else
73
- STDERR.puts("ERROR, what to do with #{resp}")
74
- nil
75
- end
76
- end
77
- end
78
-
79
- end
@@ -1,138 +0,0 @@
1
- require 'yadis/yadis'
2
-
3
- class YadisServiceManager
4
-
5
- attr_reader :starting_url, :yadis_url, :services, :session_key, :current
6
-
7
- def initialize(starting_url, yadis_url, services)
8
- @starting_url = starting_url
9
- @yadis_url = yadis_url
10
- @services = services
11
- @current = nil
12
- end
13
-
14
- def next
15
- @current = @services.shift
16
- end
17
-
18
- def for_url?(url)
19
- url == @starting_url or url == @yadis_url
20
- end
21
-
22
- def started?
23
- not @current.nil?
24
- end
25
-
26
- def length
27
- @services.length
28
- end
29
-
30
- end
31
-
32
- class Discovery
33
-
34
- @@default_suffix = nil
35
- @@prefix = '_yadis_services_'
36
-
37
- def initialize(session, url, session_key_siffix=nil)
38
- @session = session
39
- @url = url
40
- @session_key = @@prefix + (session_key_suffix or @@default_suffix)
41
- end
42
-
43
- def next_service(discover_block)
44
- manager = self.get_manager
45
- if manager and manager.length <= 0
46
- self.destroy_manager
47
- manager = nil
48
- end
49
-
50
- unless manager
51
- begin
52
- yadis_url, services = self.discover
53
- rescue YADISParseError, YADISHTTPError
54
- manager = nil
55
- else
56
- manager = self.create_manager(services, yadis_url)
57
- end
58
- end
59
-
60
- if manager
61
- service = manager.next
62
- self.store_manager(manager)
63
- else
64
- service = nil
65
- end
66
-
67
- return service
68
- end
69
-
70
- def finish
71
- manager = self.get_manager
72
- return nil unless manager
73
-
74
- service = manager.current
75
- self.destroy_manager
76
- return service
77
- end
78
-
79
- def get_manager
80
- manager = @session[@session_key]
81
-
82
- # make sure we've got the right manager here
83
- if manager and manager.for_url?(@url)
84
- return manager
85
- end
86
-
87
- return nil
88
- end
89
-
90
- def create_manager(services, yadis_url=nil)
91
- if self.get_manager
92
- raise ArgumentError, "There is already a manager for #{@url}"
93
- end
94
-
95
- if services.length > 0
96
- manager = YadisServiceManager.new(@url, yadis_url, services)
97
- self.store_manager(manager)
98
- else
99
- manager = nil
100
- end
101
-
102
- return manager
103
- end
104
-
105
- def destroy_manager
106
- if self.get_manager
107
- begin
108
- @session.delete(@session_key)
109
- rescue
110
- # sometimes Hash like session objects don't have a delete
111
- # method. We handle that case by assigning nil to the session[key]
112
- @session[@session_key] = nil
113
- end
114
- end
115
- end
116
-
117
- def store_manager(manager)
118
- @session[@session_key] = manager
119
- end
120
-
121
- # The filter argument is a Proc that will be used to call
122
- # YADIS.filter_services. See the documentation for YADIS.filter_services
123
- # for more information about writing filters.
124
- def discover(filter=nil)
125
- y = YADIS.new(@url)
126
-
127
- # a default filter which sends through everything. you should
128
- # probably consider writing a custom filter and passing it in.
129
- unless filter
130
- filter = lambda {|s| s}
131
- end
132
-
133
- return [y.url, y.filter_services(filter)]
134
- end
135
-
136
- end
137
-
138
-
@@ -1,24 +0,0 @@
1
- require 'rexml/document'
2
-
3
- # Class representing an XRD Service element.
4
- class ServiceEndpoint
5
-
6
- attr_accessor :service_types, :uri, :yadis_uri, :element, :yadis
7
-
8
- def initialize
9
- @service_types = []
10
- @uri = nil
11
- @yadis_uri = nil
12
- @element = nil
13
- @yadis_uri = nil
14
- end
15
-
16
- def match_type_uris(type_uris)
17
- type_uris.find_all {|t| @service_types.member?(t)}
18
- end
19
-
20
- def ==(other)
21
- return self.instance_variables == other.instance_variables
22
- end
23
-
24
- end
@@ -1,128 +0,0 @@
1
- require 'rexml/document'
2
- require 'yadis/service'
3
-
4
- # Class that handles XRDS parsing and XRD Service element extraction.
5
-
6
- module XRDSUtil
7
-
8
- @@default_namespace = 'xri://$xrd*($v*2.0)'
9
- @@xrds_namespace = {'xrds' => 'xri://$xrds'}
10
-
11
- def last_xrd(root_element)
12
- REXML::XPath.match(root_element, '/xrds:XRDS/XRD',
13
- @@xrds_namespace)[-1]
14
- end
15
-
16
- end
17
-
18
- class XRDS
19
-
20
- include XRDSUtil
21
- attr_reader :xml
22
-
23
- # Method for producing a valid XRDS object. Accepts an XML
24
- # String. Returns an XRDS object on success, or nil on failure.
25
- # Same as calling XRDS.new, but does not rails ArgumentErrors.
26
- def XRDS.parse(xml)
27
- begin
28
- return new(xml)
29
- rescue
30
- return nil
31
- end
32
- end
33
-
34
- # Create a new XRDS object. Raises ArgumentError if xml_text is
35
- # malformed or invalid XRDS.
36
- def initialize(xml_text)
37
- parse_xml(xml_text)
38
- end
39
-
40
- def parse_xml(xml_text)
41
- begin
42
- xml = @xml = REXML::Document.new(xml_text)
43
- rescue
44
- raise ArgumentError, "Can't parse XRDS"
45
- end
46
-
47
- if xml.root.nil?
48
- raise ArgumentError, "No document root"
49
- end
50
-
51
- xmlns = xml.root.attributes['xmlns']
52
- if xmlns != @@default_namespace
53
- raise ArgumentError, "Unknown XRID version #{xmlns.to_s}"
54
- end
55
-
56
- xrd = self.last_xrd(xml.root)
57
- raise ArgumentError, "No XRD Elements found" if xrd.nil?
58
-
59
- @services = {} # keyed by [service_priority, uri_priority]
60
- xrd.elements.each('Service') {|s| _create_services(s)}
61
- end
62
-
63
-
64
- # Returns an Array of ServiceEndpoint objects, sorted by priority. Highest
65
- # priority is at element 0.
66
- def services
67
- s = []
68
-
69
- @services.keys.sort.each do |key|
70
- services_list = @services[key].dup
71
-
72
- # randomize services with the same priority
73
- while services_list.length > 0
74
- s << services_list.delete_at((rand * services_list.length).to_i)
75
- end
76
-
77
- end
78
-
79
- return s
80
- end
81
-
82
- private
83
-
84
- # create services objects
85
- def _create_services(service_element)
86
- service = ServiceEndpoint.new
87
- service.element = service_element
88
- service.uri = nil
89
- service.service_types = []
90
-
91
- service_element.elements.each('Type') do |t|
92
- service.service_types << t.text.strip
93
- end
94
-
95
- sp = service_element.attributes['priority']
96
- service_priority = sp ? sp.to_i : -1
97
-
98
- if service.element.elements['URI']
99
- service.element.elements.each('URI') do |uri|
100
- _service = service.dup
101
- _service.uri = uri.text.strip
102
-
103
- up = uri.attributes['priority']
104
- uri_priority = up ? up.to_i : -1
105
- priority = [service_priority, uri_priority]
106
-
107
- _add_service(priority, _service)
108
- end
109
-
110
- else
111
- priority = [service_priority, -1]
112
- _add_service(priority, service)
113
-
114
- end
115
-
116
- end
117
-
118
- def _add_service(priority, service)
119
- unless @services.has_key?(priority)
120
- @services[priority] = []
121
- end
122
-
123
- # services with the same priority are appended to the list
124
- @services[priority] << service
125
- end
126
-
127
- end
128
-
@@ -1,104 +0,0 @@
1
- require 'yadis/xrds'
2
- require 'yadis/fetcher'
3
- require 'yadis/parsehtml'
4
-
5
- class YADISParseError < StandardError; end
6
- class YADISHTTPError < StandardError; end
7
-
8
- class YADIS
9
-
10
- @@ca_path = nil
11
- attr_accessor :uri, :xrds_uri, :xrds
12
-
13
- # Discover services for a given URI. Please note that no normalization
14
- # will be done to the passed in URI, it should be a textually
15
- # valid URI string before calling discover.
16
- #
17
- # Returns nil if no XRDS was found, or a YADIS object on success. This
18
- # method is essentially the same as YADIS.new, but does not raise any
19
- # exceptions.
20
- def YADIS.discover(uri)
21
- return nil unless uri
22
- begin
23
- return YADIS.new(uri)
24
- rescue
25
- return nil
26
- end
27
- end
28
-
29
- # Set the path to a certificate authority pem file, for verifying
30
- # server certificates of HTTPS pages. If you are interested in verifying
31
- # certs like the mozilla web browser, have a look at the files here:
32
- #
33
- # http://curl.haxx.se/docs/caextract.html
34
- def YADIS.ca_path=(ca_path)
35
- ca_path = ca_path.to_s
36
- if File.exists?(ca_path)
37
- @@ca_path = ca_path
38
- else
39
- raise ArgumentError, "#{ca_path} is not a valid file path"
40
- end
41
- end
42
-
43
- # Discover services for a URI using the Yadis protocol. +uri+ should
44
- # be a valid URI represented as a string. This method may raise
45
- # YADISParseError in the case of an invalid or unparsable XRDS file,
46
- # or YADISHTTPError is the URI cannot be fetched.
47
- def initialize(uri)
48
- http = NetHTTPFetcher.new
49
- http.ca_path = @@ca_path if @@ca_path
50
- headers = {'Accept' => 'application/xrds+xml'}
51
-
52
- response = http.get(uri, headers)
53
- raise YADISHTTPError, "Could not fetch #{uri}" if response.nil?
54
-
55
- uri, resp_payload = response
56
- xrds_uri = uri
57
-
58
- header = resp_payload['x-xrds-location']
59
- header = resp_payload['x-yadis-location'] if header.nil?
60
-
61
- if header
62
- xrds_uri = header
63
- response = http.get(xrds_uri)
64
- raise YADISHTTPError, "Could not fetch XRDS #{xrds_uri}" if response.nil?
65
- resp_payload = response[1]
66
- end
67
-
68
- unless resp_payload['content-type'] == 'application/xrds+xml'
69
- loc = html_yadis_location(resp_payload.body)
70
- unless loc.nil?
71
- xrds_uri, resp_payload = http.get(loc)
72
- end
73
- end
74
-
75
- xrds = XRDS.parse(resp_payload.body)
76
- raise YADISParseError, "Bad XRDS" if xrds.nil?
77
-
78
- @uri = uri
79
- @xrds_uri = xrds_uri
80
- @xrds = xrds
81
- end
82
-
83
- # Returns an Array Service objects sorted by priority.
84
- def services
85
- @xrds.services.each {|s| s.yadis = self}
86
- @xrds.services
87
- end
88
-
89
- # Returns a list of services, ordered by priority,
90
- # that match the filter. filter is a Proc object that produces
91
- # ServiceEnpoint objects, subclasses of ServiceEnpoint or nil.
92
- # This method is useful for extracting several types of services while
93
- # maintaining priority, for example you may write a filter Proc to extract
94
- # OpenID and LID ServiceEnpoint objects.
95
- def filter_services(filter)
96
- # product a list of filtered ServiceEndpoint objects. filtered
97
- # will contain a list of nil or ServiceEnpoint (subclasses) objects.
98
- filtered = self.services.collect {|s| filter.call(s)}
99
-
100
- # return all object in filtered that are not nil
101
- return filtered.find_all {|s| s}
102
- end
103
-
104
- end