blather 0.4.15 → 0.4.16

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.
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