blather 0.4.15 → 0.4.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.autotest +13 -0
  2. data/.gitignore +18 -0
  3. data/CHANGELOG +150 -0
  4. data/Gemfile +4 -0
  5. data/Rakefile +32 -0
  6. data/TODO.md +2 -0
  7. data/blather.gemspec +49 -0
  8. data/lib/blather.rb +3 -0
  9. data/lib/blather/client/client.rb +139 -1
  10. data/lib/blather/client/dsl.rb +16 -0
  11. data/lib/blather/core_ext/active_support.rb +1 -1
  12. data/lib/blather/core_ext/ipaddr.rb +19 -0
  13. data/lib/blather/file_transfer/s5b.rb +8 -0
  14. data/lib/blather/roster_item.rb +5 -2
  15. data/lib/blather/stanza/disco.rb +7 -0
  16. data/lib/blather/stanza/disco/disco_info.rb +13 -19
  17. data/lib/blather/stanza/disco/disco_items.rb +5 -11
  18. data/lib/blather/stanza/presence.rb +15 -5
  19. data/lib/blather/stanza/presence/c.rb +103 -0
  20. data/lib/blather/stanza/x.rb +2 -4
  21. data/lib/blather/version.rb +3 -0
  22. data/lib/blather/xmpp_node.rb +8 -0
  23. data/spec/blather/client/client_spec.rb +87 -1
  24. data/spec/blather/client/dsl/pubsub_spec.rb +2 -2
  25. data/spec/blather/client/dsl_spec.rb +85 -5
  26. data/spec/blather/core_ext/nokogiri_spec.rb +1 -1
  27. data/spec/blather/errors/sasl_error_spec.rb +1 -1
  28. data/spec/blather/errors/stanza_error_spec.rb +2 -2
  29. data/spec/blather/errors/stream_error_spec.rb +2 -2
  30. data/spec/blather/errors_spec.rb +1 -1
  31. data/spec/blather/file_transfer_spec.rb +2 -2
  32. data/spec/blather/jid_spec.rb +1 -1
  33. data/spec/blather/roster_item_spec.rb +1 -1
  34. data/spec/blather/roster_spec.rb +1 -1
  35. data/spec/blather/stanza/discos/disco_info_spec.rb +1 -11
  36. data/spec/blather/stanza/discos/disco_items_spec.rb +1 -6
  37. data/spec/blather/stanza/iq/command_spec.rb +3 -3
  38. data/spec/blather/stanza/iq/ibb_spec.rb +2 -2
  39. data/spec/blather/stanza/iq/query_spec.rb +1 -1
  40. data/spec/blather/stanza/iq/roster_spec.rb +1 -1
  41. data/spec/blather/stanza/iq/s5b_spec.rb +2 -2
  42. data/spec/blather/stanza/iq/si_spec.rb +2 -2
  43. data/spec/blather/stanza/iq/vcard_spec.rb +3 -3
  44. data/spec/blather/stanza/iq_spec.rb +1 -1
  45. data/spec/blather/stanza/message_spec.rb +2 -2
  46. data/spec/blather/stanza/presence/c_spec.rb +46 -0
  47. data/spec/blather/stanza/presence/status_spec.rb +1 -1
  48. data/spec/blather/stanza/presence/subscription_spec.rb +1 -1
  49. data/spec/blather/stanza/presence_spec.rb +1 -1
  50. data/spec/blather/stanza/pubsub/affiliations_spec.rb +2 -2
  51. data/spec/blather/stanza/pubsub/create_spec.rb +3 -3
  52. data/spec/blather/stanza/pubsub/event_spec.rb +2 -2
  53. data/spec/blather/stanza/pubsub/items_spec.rb +2 -2
  54. data/spec/blather/stanza/pubsub/publish_spec.rb +2 -2
  55. data/spec/blather/stanza/pubsub/retract_spec.rb +2 -2
  56. data/spec/blather/stanza/pubsub/subscribe_spec.rb +2 -2
  57. data/spec/blather/stanza/pubsub/subscription_spec.rb +3 -3
  58. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +2 -2
  59. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +2 -2
  60. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +2 -2
  61. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +3 -3
  62. data/spec/blather/stanza/pubsub_owner_spec.rb +2 -2
  63. data/spec/blather/stanza/pubsub_spec.rb +2 -8
  64. data/spec/blather/stanza/x_spec.rb +1 -6
  65. data/spec/blather/stanza_spec.rb +1 -1
  66. data/spec/blather/stream/client_spec.rb +3 -3
  67. data/spec/blather/stream/component_spec.rb +1 -1
  68. data/spec/blather/stream/parser_spec.rb +1 -1
  69. data/spec/blather/xmpp_node_spec.rb +1 -1
  70. data/spec/spec_helper.rb +5 -12
  71. data/yard/templates/default/class/html/handlers.erb +18 -0
  72. data/yard/templates/default/class/setup.rb +10 -0
  73. data/yard/templates/default/class/text/handlers.erb +1 -0
  74. metadata +123 -13
  75. data/lib/test.rb +0 -55
data/.autotest ADDED
@@ -0,0 +1,13 @@
1
+ Autotest.add_hook :initialize do |at|
2
+ ignore = %w[.git examples ext pkg .DS_Store CHANGELOG LICENSE VERSION.yml README.rdoc .autotest Rakefile blather.gemspec]
3
+
4
+ ignore.each { |exception| at.add_exception(exception) }
5
+
6
+ at.clear_mappings
7
+
8
+ at.add_mapping(%r%^spec/.*_spec.rb$%) { |filename, _| filename }
9
+ at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m| ["spec/#{m[1]}_spec.rb"] }
10
+ at.add_mapping(%r%^spec/(spec_helper|shared/.*)\.rb$%) {
11
+ at.files_matching %r%^spec/.*_spec\.rb$%
12
+ }
13
+ end
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ pkg
2
+ Manifest
3
+ doc
4
+ coverage
5
+ *.bundle
6
+ Gemfile.lock
7
+ mkmf.log
8
+ *.o
9
+ Makefile
10
+ rdoc
11
+ *.gem
12
+ *.log
13
+ *.pid
14
+ notes
15
+ .yardoc
16
+ *.rbc
17
+ lib/.DS_Store
18
+ vendor
data/CHANGELOG ADDED
@@ -0,0 +1,150 @@
1
+ v0.4.16
2
+ Feature(benlangfeld): switch from jeweler to bundler
3
+ Feature(benlangfeld): add cap support (XEP-0115)
4
+ Bugfix(sprsquish): Better equality checking
5
+ Bugfix(sprsquish): Fix #to_proc
6
+ Bugfix(mironov): Skip private IPs by default
7
+
8
+ v0.4.15
9
+ Feature(mironov): Implement XEP-0054: vcard-temp
10
+ Feature(benlangfeld): Basic support for PubSub subscription notifications as PubSub events
11
+ Feature(mironov): Ability to clear handlers
12
+ Feature(mironov): Implement incoming file transfers (XEP-0096, XEP-0065, XEP-0047)
13
+ Bugfix(mironov): Fix for importing messages with chat states
14
+ Bugfix(mironov): Added Symbol#to_proc method to work on ruby 1.8.6
15
+ Bugfix(mironov): Fix roster items .status method to return highest priority presence
16
+ Bugfix(mironov): Remove old unavailable presences while adding new one
17
+ Bugfix(mironov): Use Nokogiri::XML::ParseOptions::NOENT to prevent double-encoding of entities
18
+ Bugfix(benlangfeld): Disco Info Identities should have an xml:lang attribute
19
+ Bugfix(mironov): Fix lookup path for ruby 1.9
20
+ Bugfix(mironov): stanza_error.to_node must set type of the error
21
+ Bugfix(mironov): Allow message to have iq child
22
+ Bugfix(mironov): Find xhtml body in messages sent from iChat 5.0.3
23
+
24
+ v0.4.14
25
+ Tests: get specs fully passing on rubinius
26
+ Feature(mironov): Implement XEP-0085 Chat State Notifications
27
+ Bugfix(mironov): send stanzas unformatted
28
+ Bugfix(mironov): Message#xhtml uses inner_html so tags aren't escaped
29
+ Bugfix(mironov): Message#xhtml= now works with multiple root nodes
30
+
31
+ v0.4.13
32
+ Bugfix: Place form child of command inside command element
33
+
34
+ v0.4.12
35
+ API Change: Switch order of var and type arguments to X::Field.new since var is always required but type is not
36
+ API Change: PubSub payloads can be strings or nodes and can be set nil. PubSub#payload will always return a string
37
+ Feature: Add forms to Message stanzas
38
+
39
+ v0.4.11
40
+ Bugfix: command nodes where generating the wrong xml
41
+ Bugfix: x nodes where generating the wrong xml
42
+ Feature: ability to set identities and features on disco info nodes
43
+ Feature: ability to set items on disco item nodes
44
+
45
+ v0.4.10
46
+ no change
47
+
48
+ v0.4.9
49
+ Feature: XEP-0004 x:data (benlangfeld)
50
+ Feature: XEP-0050 Ad-Hoc commands (benlangfeld)
51
+ Minor bugfixes for the specs
52
+
53
+ v0.4.8
54
+ Feature: add xhtml getter/setter to Message stanza
55
+ Bugfix: heirarchy -> hierarchy spelling mistake
56
+ Hella documentation
57
+
58
+ v0.4.7
59
+ Update to work with Nokogiri 1.4.0
60
+
61
+ v0.4.6
62
+ Bugfix: prioritize authentication mechanisms
63
+
64
+ v0.4.5
65
+ Bugfix: Change DSL#write to DSL#write_to_stream. Previous way was messing with YAML
66
+
67
+ v0.4.4
68
+ Add "disconnected" handler type to handle connection termination
69
+ Bugfix: Fix error with pubsub using the wrong client connection
70
+
71
+ v0.4.3
72
+ Bugfix: status stanza with a blank state will be considered :available (GH-23)
73
+ Bugfix: ensure regexp guards try to match against a string (GH-24)
74
+ Stream creation is now evented. The stream object will be sent to #post_init
75
+ Parser debugging disabled by default
76
+ Update parser to work with Nokogiri 1.3.2
77
+ Bugfix: discover helper now calls the correct method on client
78
+ Bugfix: ensure XMPPNode#inherit properly sets namespaces on inherited nodes
79
+ Bugfix: xpath guards with namespaces work properly (GH-25)
80
+
81
+ v0.4.2
82
+ Fix -D option to actually put Blather in debug mode
83
+ Stanzas over a client connection will either have the full JID or no JID
84
+ Regexp guards can be anything that implements #last_match (Regexp or Oniguruma)
85
+ Add "halt" and "pass" to allow handlers to either halt the handler chain or pass to the next handler
86
+ Fix default status handler so it doesn't eat the stanza
87
+ Add before and after filters. Filters, like handlers, can have guards.
88
+
89
+ v0.4.1
90
+ Bugfix in roster: trying to call the wrong method on client
91
+
92
+ v0.4.0
93
+ Switch from LibXML-Ruby to Nokogiri
94
+ Update test suite to run on Ruby 1.9
95
+ Add "<<" style writer to the DSL to provide for chaining outbound writes
96
+ SRV lookup support
97
+ Add XPath type of handler guard
98
+ PubSub support
99
+
100
+ v0.3.4
101
+ Remove unneeded functions from the push parser.
102
+ Create a ParseWarning error that doesn't kill the stream.
103
+ When a parse error comes in the reply should let the other side know it screwed up before dying.
104
+ Add the LibXML::XML::Error node to the ParseError/ParseWarning objects.
105
+
106
+ v0.3.3
107
+ Fix the load error related to not pushing Blather's dir into the load path
108
+
109
+ v0.3.2
110
+ Switch the push parser from chunking to streaming.
111
+ Don't push Blather's dir into the load paths
112
+
113
+ v0.3.1
114
+ Small changes to the DSL due to handler collisions:
115
+ "status" -> "set_status"
116
+ "roster" -> "my_roster"
117
+ Small changes to the Blather::Client API to keep it feeling more like EM's API:
118
+ #stream_started -> #post_init
119
+ #call -> #receive_data
120
+ #stop -> #close
121
+ #stopped -> #unbind
122
+ Refactored some of the code internal to Blather::Client
123
+ Added command line option handler to default use method (see README)
124
+ require libxml-ruby >=1.1.2 (1.1.3 has an inconsistent malloc err on OS X 10.5)
125
+ complete specs
126
+ add single process ping-pong example
127
+
128
+ v0.3.0
129
+ Remove autotest discover.rb (created all sorts of conflicts)
130
+ Added Hash with Array guard
131
+ Added a hirrarchy printer to examples directory
132
+ Moved Disco to be in the Stanza namespace (staves off deeply namespaced classes)
133
+ Namespaced the DSL methods to Blather::DSL. These can be included in any object you like now. "require 'blather/client'" will still include them directly in Kernel to keep the simple one-file dsl
134
+ Stopped doing one class per error type. This created a giant hierarchy tree that was just unnecessary. The error name is now #name. Errors can be matched with a combination of handler and guard.
135
+ Fixed XML namespaces. Previous versions weren't actually adding the node to the namespace making xpath queries inconsistent at best.
136
+ Added support for anonymous authentication by providing a blank node on the jid ("@[host]")
137
+
138
+ v0.2.3
139
+ Go back to using the master branch for gems (stupid mistake)
140
+
141
+ v0.2.2
142
+ Switch to Jeweler.
143
+ Move from custom libxml to just a custom push parser
144
+ Add guards to handlers
145
+
146
+ v0.2.1 Upgrade to libxml 0.9.7
147
+
148
+ v0.2 Overhaul the DSL to look more like Sinatra
149
+
150
+ v0.1 Initial release (birth!)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in testgem.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require 'bundler'
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ require 'rake/testtask'
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.libs << 'lib' << 'spec'
10
+ test.pattern = 'spec/**/*_spec.rb'
11
+ test.verbose = true
12
+ end
13
+
14
+ require 'rcov/rcovtask'
15
+ Rcov::RcovTask.new do |test|
16
+ test.libs << 'spec'
17
+ test.pattern = 'spec/**/*_spec.rb'
18
+ test.rcov_opts += ['--exclude \/Library\/Ruby,spec\/', '--xrefs']
19
+ test.verbose = true
20
+ end
21
+
22
+ require 'yard'
23
+ YARD::Tags::Library.define_tag 'Blather handler', :handler, :with_name
24
+ YARD::Templates::Engine.register_template_path 'yard/templates'
25
+
26
+ YARD::Rake::YardocTask.new do |t|
27
+ t.options = ['--no-private', '-m', 'markdown', '-o', './doc/public/yard']
28
+ end
29
+
30
+ desc 'Generate documentation'
31
+ task :doc => :yard
32
+ task :default => :test
data/TODO.md ADDED
@@ -0,0 +1,2 @@
1
+ * Cleanup implementation of X stanzas
2
+ * Cleanup implementation of PubSub Subscribe Events
data/blather.gemspec ADDED
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "blather/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "blather"
7
+ s.version = Blather::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jeff Smick"]
10
+ s.email = %q{sprsquish@gmail.com}
11
+ s.date = %q{2010-09-02}
12
+ s.homepage = "http://github.com/sprsquish/blather"
13
+ s.summary = %q{Simpler XMPP built for speed}
14
+ s.description = %q{An XMPP DSL for Ruby written on top of EventMachine and Nokogiri}
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.rdoc_options = %w{--charset=UTF-8}
22
+ s.extra_rdoc_files = %w{LICENSE README.md}
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 3
27
+
28
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
29
+ s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.6"])
30
+ s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.0"])
31
+
32
+ s.add_development_dependency(%q<minitest>, ["~> 1.7.1"])
33
+ s.add_development_dependency(%q<mocha>, ["~> 0.9.12"])
34
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
35
+ s.add_development_dependency(%q<rcov>, ["~> 0.9.9"])
36
+ s.add_development_dependency(%q<yard>, ["~> 0.6.1"])
37
+ s.add_development_dependency(%q<bluecloth>, ["~> 2.1.0"])
38
+ s.add_development_dependency(%q<rake>)
39
+ else
40
+ s.add_dependency(%q<eventmachine>, [">= 0.12.6"])
41
+ s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
42
+ s.add_dependency(%q<minitest>, [">= 1.7.1"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<eventmachine>, [">= 0.12.6"])
46
+ s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
47
+ s.add_dependency(%q<minitest>, [">= 1.7.1"])
48
+ end
49
+ end
data/lib/blather.rb CHANGED
@@ -3,12 +3,14 @@
3
3
  rubygems
4
4
  eventmachine
5
5
  nokogiri
6
+ ipaddr
6
7
  digest/md5
7
8
  digest/sha1
8
9
  logger
9
10
 
10
11
  blather/core_ext/active_support
11
12
  blather/core_ext/eventmachine
13
+ blather/core_ext/ipaddr
12
14
  blather/core_ext/nokogiri
13
15
 
14
16
  blather/errors
@@ -37,6 +39,7 @@
37
39
  blather/stanza/disco/disco_items
38
40
  blather/stanza/message
39
41
  blather/stanza/presence
42
+ blather/stanza/presence/c
40
43
  blather/stanza/presence/status
41
44
  blather/stanza/presence/subscription
42
45
 
@@ -33,7 +33,8 @@ module Blather
33
33
  #
34
34
  class Client
35
35
  attr_reader :jid,
36
- :roster
36
+ :roster,
37
+ :caps
37
38
 
38
39
  # Create a new client and set it up
39
40
  #
@@ -56,6 +57,7 @@ module Blather
56
57
  @tmp_handlers = {}
57
58
  @filters = {:before => [], :after => []}
58
59
  @roster = Roster.new self
60
+ @caps = Caps.new
59
61
 
60
62
  setup_initial_handlers
61
63
  end
@@ -313,6 +315,142 @@ module Blather
313
315
  end
314
316
  end
315
317
  end
318
+
319
+ class Caps < Blather::Stanza::DiscoInfo
320
+ def self.new
321
+ super :result
322
+ end
323
+
324
+ def ver
325
+ generate_ver identities, features
326
+ end
327
+
328
+ def node=(node)
329
+ @bare_node = node
330
+ super "#{node}##{ver}"
331
+ end
332
+
333
+ def identities=(identities)
334
+ super identities
335
+ regenerate_full_node
336
+ end
337
+
338
+ def features=(features)
339
+ super features
340
+ regenerate_full_node
341
+ end
342
+
343
+ def c
344
+ Blather::Stanza::Presence::C.new @bare_node, ver
345
+ end
346
+
347
+ private
348
+
349
+ def regenerate_full_node
350
+ self.node = @bare_node
351
+ end
352
+
353
+ def generate_ver_str(identities, features, forms = [])
354
+ # 1. Initialize an empty string S.
355
+ s = ''
356
+
357
+ # 2. Sort the service discovery identities by category and
358
+ # then by type (if it exists) and then by xml:lang (if it
359
+ # exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
360
+ # [NAME]. Note that each slash is included even if the TYPE,
361
+ # LANG, or NAME is not included.
362
+ identities.sort! do |identity1, identity2|
363
+ cmp_result = nil
364
+ [:category, :type, :xml_lang, :name].each do |field|
365
+ value1 = identity1.send(field)
366
+ value2 = identity2.send(field)
367
+
368
+ if value1 != value2
369
+ cmp_result = value1 <=> value2
370
+ break
371
+ end
372
+ end
373
+ cmp_result
374
+ end
375
+
376
+ # 3. For each identity, append the 'category/type/lang/name' to
377
+ # S, followed by the '<' character.
378
+ s += identities.collect do |identity|
379
+ [:category, :type, :xml_lang, :name].collect do |field|
380
+ identity.send(field).to_s
381
+ end.join('/') + '<'
382
+ end.join
383
+
384
+ # 4. Sort the supported service discovery features.
385
+ features.sort! { |feature1, feature2| feature1.var <=> feature2.var }
386
+
387
+ # 5. For each feature, append the feature to S, followed by the
388
+ # '<' character.
389
+ s += features.collect { |feature| feature.var.to_s + '<' }.join
390
+
391
+ # 6. If the service discovery information response includes
392
+ # XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e., by
393
+ # the XML character data of the <value/> element).
394
+ forms.sort! do |form1, form2|
395
+ fform_type1 = form1.field 'FORM_TYPE'
396
+ fform_type2 = form2.field 'FORM_TYPE'
397
+ form_type1 = fform_type1 ? fform_type1.values.to_s : nil
398
+ form_type2 = fform_type2 ? fform_type2.values.to_s : nil
399
+ form_type1 <=> form_type2
400
+ end
401
+
402
+ # 7. For each extended service discovery information form:
403
+ forms.each do |form|
404
+ # 7.1. Append the XML character data of the FORM_TYPE field's
405
+ # <value/> element, followed by the '<' character.
406
+ fform_type = form.field 'FORM_TYPE'
407
+ form_type = fform_type ? fform_type.values.to_s : nil
408
+ s += "#{form_type}<"
409
+
410
+ # 7.2. Sort the fields by the value of the "var" attribute
411
+ fields = form.fields.sort { |field1, field2| field1.var <=> field2.var }
412
+
413
+ # 7.3. For each field:
414
+ fields.each do |field|
415
+ # 7.3.1. Append the value of the "var" attribute, followed by
416
+ # the '<' character.
417
+ s += "#{field.var}<"
418
+
419
+ # 7.3.2. Sort values by the XML character data of the <value/> element
420
+ # values = field.values.sort { |value1, value2| value1 <=> value2 }
421
+
422
+ # 7.3.3. For each <value/> element, append the XML character
423
+ # data, followed by the '<' character.
424
+ # s += values.collect { |value| "#{value}<" }.join
425
+ s += "#{field.value}<"
426
+ end
427
+ end
428
+ s
429
+ end
430
+
431
+ def generate_ver(identities, features, forms = [], hash = 'sha-1')
432
+ s = generate_ver_str identities, features, forms
433
+
434
+ # 9. Compute the verification string by hashing S using the
435
+ # algorithm specified in the 'hash' attribute (e.g., SHA-1 as
436
+ # defined in RFC 3174). The hashed data MUST be generated
437
+ # with binary output and encoded using Base64 as specified in
438
+ # Section 4 of RFC 4648 (note: the Base64 output MUST NOT
439
+ # include whitespace and MUST set padding bits to zero).
440
+
441
+ # See http://www.iana.org/assignments/hash-function-text-names
442
+ hash_klass = case hash
443
+ when 'md2' then nil
444
+ when 'md5' then Digest::MD5
445
+ when 'sha-1' then Digest::SHA1
446
+ when 'sha-224' then nil
447
+ when 'sha-256' then Digest::SHA256
448
+ when 'sha-384' then Digest::SHA384
449
+ when 'sha-512' then Digest::SHA512
450
+ end
451
+ hash_klass ? [hash_klass::digest(s)].pack('m').strip : nil
452
+ end
453
+ end # Caps
316
454
  end # Client
317
455
 
318
456
  end # Blather