ruby-yadis 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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