kinetic_sdk 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/GettingStarted.md +64 -0
- data/README.md +383 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/gems/kontena-websocket-client-0.1.1/Gemfile +4 -0
- data/gems/kontena-websocket-client-0.1.1/LICENSE +190 -0
- data/gems/kontena-websocket-client-0.1.1/README.md +138 -0
- data/gems/kontena-websocket-client-0.1.1/Rakefile +6 -0
- data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark-client.rb +45 -0
- data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark-em.rb +66 -0
- data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark.rb +161 -0
- data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark.sh +17 -0
- data/gems/kontena-websocket-client-0.1.1/benchmark/websocket-echo-server.go +207 -0
- data/gems/kontena-websocket-client-0.1.1/examples/websocket-echo-client.rb +80 -0
- data/gems/kontena-websocket-client-0.1.1/kontena-websocket-client.gemspec +24 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client/connection.rb +119 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client/version.rb +13 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client.rb +848 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/error.rb +81 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/logging.rb +55 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/openssl_patch.rb +10 -0
- data/gems/kontena-websocket-client-0.1.1/lib/kontena-websocket-client.rb +15 -0
- data/gems/mime-types-3.1/Code-of-Conduct.rdoc +74 -0
- data/gems/mime-types-3.1/Contributing.rdoc +130 -0
- data/gems/mime-types-3.1/History.rdoc +658 -0
- data/gems/mime-types-3.1/Licence.rdoc +25 -0
- data/gems/mime-types-3.1/Manifest.txt +31 -0
- data/gems/mime-types-3.1/README.rdoc +202 -0
- data/gems/mime-types-3.1/Rakefile +254 -0
- data/gems/mime-types-3.1/lib/mime/type/columnar.rb +55 -0
- data/gems/mime-types-3.1/lib/mime/type.rb +573 -0
- data/gems/mime-types-3.1/lib/mime/types/_columnar.rb +135 -0
- data/gems/mime-types-3.1/lib/mime/types/cache.rb +56 -0
- data/gems/mime-types-3.1/lib/mime/types/columnar.rb +1 -0
- data/gems/mime-types-3.1/lib/mime/types/container.rb +30 -0
- data/gems/mime-types-3.1/lib/mime/types/deprecations.rb +32 -0
- data/gems/mime-types-3.1/lib/mime/types/full.rb +17 -0
- data/gems/mime-types-3.1/lib/mime/types/loader.rb +148 -0
- data/gems/mime-types-3.1/lib/mime/types/logger.rb +37 -0
- data/gems/mime-types-3.1/lib/mime/types/registry.rb +81 -0
- data/gems/mime-types-3.1/lib/mime/types.rb +228 -0
- data/gems/mime-types-3.1/lib/mime-types.rb +1 -0
- data/gems/mime-types-3.1/test/bad-fixtures/malformed +9 -0
- data/gems/mime-types-3.1/test/fixture/json.json +1 -0
- data/gems/mime-types-3.1/test/fixture/old-data +9 -0
- data/gems/mime-types-3.1/test/fixture/yaml.yaml +55 -0
- data/gems/mime-types-3.1/test/minitest_helper.rb +13 -0
- data/gems/mime-types-3.1/test/test_mime_type.rb +603 -0
- data/gems/mime-types-3.1/test/test_mime_types.rb +161 -0
- data/gems/mime-types-3.1/test/test_mime_types_cache.rb +109 -0
- data/gems/mime-types-3.1/test/test_mime_types_class.rb +155 -0
- data/gems/mime-types-3.1/test/test_mime_types_lazy.rb +43 -0
- data/gems/mime-types-3.1/test/test_mime_types_loader.rb +32 -0
- data/gems/mime-types-data-3.2016.0521/Code-of-Conduct.md +75 -0
- data/gems/mime-types-data-3.2016.0521/Contributing.md +157 -0
- data/gems/mime-types-data-3.2016.0521/History.md +351 -0
- data/gems/mime-types-data-3.2016.0521/Licence.md +25 -0
- data/gems/mime-types-data-3.2016.0521/Manifest.txt +18 -0
- data/gems/mime-types-data-3.2016.0521/README.md +61 -0
- data/gems/mime-types-data-3.2016.0521/Rakefile +80 -0
- data/gems/mime-types-data-3.2016.0521/data/mime-types.json +1 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.content_type.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.docs.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.encoding.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.flags.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.friendly.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.pext.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.use_instead.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/data/mime.xrefs.column +1964 -0
- data/gems/mime-types-data-3.2016.0521/lib/mime/types/data.rb +21 -0
- data/gems/mime-types-data-3.2016.0521/lib/mime-types-data.rb +3 -0
- data/gems/multipart-post-2.0.0/Gemfile +14 -0
- data/gems/multipart-post-2.0.0/History.txt +60 -0
- data/gems/multipart-post-2.0.0/Manifest.txt +9 -0
- data/gems/multipart-post-2.0.0/README.md +77 -0
- data/gems/multipart-post-2.0.0/Rakefile +9 -0
- data/gems/multipart-post-2.0.0/lib/composite_io.rb +108 -0
- data/gems/multipart-post-2.0.0/lib/multipart_post.rb +9 -0
- data/gems/multipart-post-2.0.0/lib/multipartable.rb +29 -0
- data/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb +27 -0
- data/gems/multipart-post-2.0.0/lib/parts.rb +96 -0
- data/gems/multipart-post-2.0.0/multipart-post.gemspec +22 -0
- data/gems/multipart-post-2.0.0/test/multibyte.txt +1 -0
- data/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb +110 -0
- data/gems/multipart-post-2.0.0/test/test_composite_io.rb +115 -0
- data/gems/multipart-post-2.0.0/test/test_parts.rb +86 -0
- data/gems/parallel-1.12.1/MIT-LICENSE.txt +20 -0
- data/gems/parallel-1.12.1/lib/parallel/processor_count.rb +93 -0
- data/gems/parallel-1.12.1/lib/parallel/version.rb +3 -0
- data/gems/parallel-1.12.1/lib/parallel.rb +500 -0
- data/gems/ruby-progressbar-1.9.0/LICENSE.txt +19 -0
- data/gems/ruby-progressbar-1.9.0/README.md +38 -0
- data/gems/ruby-progressbar-1.9.0/Rakefile +2 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/base.rb +183 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/calculators/length.rb +99 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/calculators/running_average.rb +9 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/bar.rb +96 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/percentage.rb +29 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/rate.rb +43 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/time.rb +107 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/title.rb +13 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components.rb +5 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/errors/invalid_progress_error.rb +4 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/formatter.rb +27 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/molecule.rb +59 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/string.rb +36 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format.rb +3 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/output.rb +68 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/non_tty.rb +47 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/null.rb +33 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/tty.rb +32 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/progress.rb +118 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/refinements/enumerator.rb +25 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/refinements.rb +1 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/throttle.rb +25 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/time.rb +30 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/timer.rb +72 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/version.rb +3 -0
- data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar.rb +18 -0
- data/gems/slugify-1.0.7/README +18 -0
- data/gems/slugify-1.0.7/lib/slugify.rb +1012 -0
- data/gems/slugify-1.0.7/lib/slugify_string.rb +11 -0
- data/gems/slugify-1.0.7/tests/slugify_test.rb +116 -0
- data/gems/slugify-1.0.7/tests/string_slugify_test.rb +23 -0
- data/gems/websocket-driver-0.6.5/CHANGELOG.md +123 -0
- data/gems/websocket-driver-0.6.5/LICENSE.md +22 -0
- data/gems/websocket-driver-0.6.5/README.md +369 -0
- data/gems/websocket-driver-0.6.5/examples/tcp_server.rb +28 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/Makefile +264 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/WebsocketMaskService.java +55 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/extconf.rb +4 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.bundle +0 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.c +41 -0
- data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.o +0 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/client.rb +140 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/draft75.rb +102 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/draft76.rb +96 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/event_emitter.rb +54 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/headers.rb +45 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi/frame.rb +20 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi/message.rb +31 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb +406 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/proxy.rb +68 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/server.rb +80 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver/stream_reader.rb +55 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/driver.rb +199 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/http/headers.rb +112 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/http/request.rb +45 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/http/response.rb +29 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/http.rb +15 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/mask.rb +14 -0
- data/gems/websocket-driver-0.6.5/lib/websocket/websocket_mask.rb +2 -0
- data/gems/websocket-driver-0.6.5/lib/websocket_mask.bundle +0 -0
- data/gems/websocket-driver-0.6.5-java/CHANGELOG.md +123 -0
- data/gems/websocket-driver-0.6.5-java/LICENSE.md +22 -0
- data/gems/websocket-driver-0.6.5-java/README.md +369 -0
- data/gems/websocket-driver-0.6.5-java/examples/tcp_server.rb +28 -0
- data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/WebsocketMaskService.java +55 -0
- data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/extconf.rb +4 -0
- data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/websocket_mask.c +41 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/client.rb +140 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/draft75.rb +102 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/draft76.rb +96 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/event_emitter.rb +54 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/headers.rb +45 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi/frame.rb +20 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi/message.rb +31 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi.rb +406 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/proxy.rb +68 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/server.rb +80 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/stream_reader.rb +55 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/driver.rb +199 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/http/headers.rb +112 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/http/request.rb +45 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/http/response.rb +29 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/http.rb +15 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/mask.rb +14 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket/websocket_mask.rb +2 -0
- data/gems/websocket-driver-0.6.5-java/lib/websocket_mask.jar +0 -0
- data/gems/websocket-extensions-0.1.3/CHANGELOG.md +15 -0
- data/gems/websocket-extensions-0.1.3/LICENSE.md +20 -0
- data/gems/websocket-extensions-0.1.3/README.md +313 -0
- data/gems/websocket-extensions-0.1.3/lib/websocket/extensions/parser.rb +111 -0
- data/gems/websocket-extensions-0.1.3/lib/websocket/extensions.rb +181 -0
- data/lib/kinetic-sdk.rb +1 -0
- data/lib/kinetic_sdk/bridgehub/bridgehub-sdk.rb +80 -0
- data/lib/kinetic_sdk/bridgehub/lib/access_keys.rb +67 -0
- data/lib/kinetic_sdk/bridgehub/lib/bridge.rb +69 -0
- data/lib/kinetic_sdk/discussions/discussions-sdk.rb +165 -0
- data/lib/kinetic_sdk/discussions/lib/discussions.rb +107 -0
- data/lib/kinetic_sdk/discussions/lib/invitations.rb +120 -0
- data/lib/kinetic_sdk/discussions/lib/messages.rb +190 -0
- data/lib/kinetic_sdk/discussions/lib/meta.rb +14 -0
- data/lib/kinetic_sdk/discussions/lib/participants.rb +64 -0
- data/lib/kinetic_sdk/discussions/lib/related_items.rb +54 -0
- data/lib/kinetic_sdk/discussions/lib/websockets.rb +96 -0
- data/lib/kinetic_sdk/filehub/filehub-sdk.rb +80 -0
- data/lib/kinetic_sdk/filehub/lib/access_keys.rb +67 -0
- data/lib/kinetic_sdk/filehub/lib/filestores.rb +67 -0
- data/lib/kinetic_sdk/request_ce/lib/attribute_definitions.rb +153 -0
- data/lib/kinetic_sdk/request_ce/lib/bridges.rb +66 -0
- data/lib/kinetic_sdk/request_ce/lib/categories.rb +34 -0
- data/lib/kinetic_sdk/request_ce/lib/datastore_form.rb +110 -0
- data/lib/kinetic_sdk/request_ce/lib/datastore_submissions.rb +157 -0
- data/lib/kinetic_sdk/request_ce/lib/form.rb +99 -0
- data/lib/kinetic_sdk/request_ce/lib/form_types.rb +51 -0
- data/lib/kinetic_sdk/request_ce/lib/jwt.rb +55 -0
- data/lib/kinetic_sdk/request_ce/lib/kapp.rb +93 -0
- data/lib/kinetic_sdk/request_ce/lib/meta.rb +14 -0
- data/lib/kinetic_sdk/request_ce/lib/oauth.rb +37 -0
- data/lib/kinetic_sdk/request_ce/lib/security_policy_definitions.rb +157 -0
- data/lib/kinetic_sdk/request_ce/lib/space.rb +89 -0
- data/lib/kinetic_sdk/request_ce/lib/submissions.rb +215 -0
- data/lib/kinetic_sdk/request_ce/lib/system_api.rb +69 -0
- data/lib/kinetic_sdk/request_ce/lib/teams.rb +113 -0
- data/lib/kinetic_sdk/request_ce/lib/users.rb +245 -0
- data/lib/kinetic_sdk/request_ce/lib/webhook_jobs.rb +142 -0
- data/lib/kinetic_sdk/request_ce/lib/webhooks.rb +192 -0
- data/lib/kinetic_sdk/request_ce/request-ce-sdk.rb +153 -0
- data/lib/kinetic_sdk/task/lib/access_keys.rb +94 -0
- data/lib/kinetic_sdk/task/lib/categories.rb +190 -0
- data/lib/kinetic_sdk/task/lib/config.rb +202 -0
- data/lib/kinetic_sdk/task/lib/engine.rb +42 -0
- data/lib/kinetic_sdk/task/lib/environment.rb +14 -0
- data/lib/kinetic_sdk/task/lib/errors.rb +165 -0
- data/lib/kinetic_sdk/task/lib/groups.rb +112 -0
- data/lib/kinetic_sdk/task/lib/handlers.rb +105 -0
- data/lib/kinetic_sdk/task/lib/health.rb +28 -0
- data/lib/kinetic_sdk/task/lib/license.rb +52 -0
- data/lib/kinetic_sdk/task/lib/policy_rules.rb +166 -0
- data/lib/kinetic_sdk/task/lib/setup.rb +56 -0
- data/lib/kinetic_sdk/task/lib/sources.rb +134 -0
- data/lib/kinetic_sdk/task/lib/tasks.rb +17 -0
- data/lib/kinetic_sdk/task/lib/trees.rb +274 -0
- data/lib/kinetic_sdk/task/lib/users.rb +75 -0
- data/lib/kinetic_sdk/task/task-sdk.rb +92 -0
- data/lib/kinetic_sdk/utils/kinetic-http-headers.rb +150 -0
- data/lib/kinetic_sdk/utils/kinetic-http-response.rb +75 -0
- data/lib/kinetic_sdk/utils/kinetic-http.rb +552 -0
- data/lib/kinetic_sdk/utils/logger.rb +70 -0
- data/lib/kinetic_sdk/utils/random.rb +30 -0
- data/lib/kinetic_sdk/version.rb +7 -0
- data/lib/kinetic_sdk.rb +57 -0
- metadata +414 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test/unit'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/slugify'
|
4
|
+
|
5
|
+
class SlugifyTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_slugify
|
8
|
+
assert_nothing_raised do
|
9
|
+
assert_equal 'dummy', Slugify.convert('dummy')
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_equal 'abcdefghijklmno', Slugify.convert('@ABCDEFGHIJKLMNO')
|
13
|
+
assert_equal 'pqrstuvwxyz---', Slugify.convert('PQRSTUVWXYZ[\]^_')
|
14
|
+
assert_equal '-', Slugify.convert('[')
|
15
|
+
assert_equal '', Slugify.convert('\\')
|
16
|
+
assert_equal '-', Slugify.convert(']')
|
17
|
+
assert_equal '', Slugify.convert('^')
|
18
|
+
assert_equal '-', Slugify.convert('_')
|
19
|
+
assert_equal 'abcdefghijklmno', Slugify.convert('`abcdefghijklmno')
|
20
|
+
assert_equal 'pqrstuvwxyz---', Slugify.convert('pqrstuvwxyz{|}~')
|
21
|
+
assert_equal '-', Slugify.convert('{')
|
22
|
+
assert_equal '', Slugify.convert('|')
|
23
|
+
assert_equal '-', Slugify.convert('}')
|
24
|
+
assert_equal '-', Slugify.convert('~')
|
25
|
+
assert_equal 'aaaaaaaeceeeeiiii', Slugify.convert('ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ')
|
26
|
+
assert_equal 'dnoooooxouuuuythb', Slugify.convert('ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß')
|
27
|
+
assert_equal 'aaaaaaaeceeeeiiii', Slugify.convert('àáâãäåæçèéêëìíîï')
|
28
|
+
assert_equal 'onoooooouuuuythy', Slugify.convert('ðñòóôõö÷øùúûüýþÿ')
|
29
|
+
assert_equal 'aaaaaaccccccccdd', Slugify.convert('ĀāĂ㥹ĆćĈĉĊċČčĎď')
|
30
|
+
assert_equal 'ddeeeeeeeeeegggg', Slugify.convert('ĐđĒēĔĕĖėĘęĚěĜĝĞğ')
|
31
|
+
assert_equal 'gggghhhhiiiiiiii', Slugify.convert('ĠġĢģĤĥĦħĨĩĪīĬĭĮį')
|
32
|
+
assert_equal 'llijijjjkkklllllll', Slugify.convert('İıIJijĴĵĶķĸĹĺĻļĽľĿ')
|
33
|
+
assert_equal 'lllnnnnnnnnnoooo', Slugify.convert('ŀŁłŃńŅņŇňʼnŊŋŌōŎŏ')
|
34
|
+
assert_equal 'oooeoerrrrrrssssss', Slugify.convert('ŐőŒœŔŕŖŗŘřŚśŜŝŞş')
|
35
|
+
assert_equal 'ssttttttuuuuuuuu', Slugify.convert('ŠšŢţŤťŦŧŨũŪūŬŭŮů')
|
36
|
+
assert_equal 'uuuuwwyyyzzzzzzs', Slugify.convert('ŰűŲųŴŵŶŷŸŹźŻżŽžſ')
|
37
|
+
assert_equal 'bbbbccddndnd', Slugify.convert('ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏ')
|
38
|
+
assert_equal '', Slugify.convert('ƂƃƆƍƎƏ')
|
39
|
+
assert_equal 'effgiikkwnno', Slugify.convert('ƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟ')
|
40
|
+
assert_equal '', Slugify.convert('Ɣƕƚƛ')
|
41
|
+
assert_equal 'oopprsssttttttu', Slugify.convert('ƠơƢƣƤƥƦƧƨƩƪƫƬƭƫƮƯ')
|
42
|
+
assert_equal '', Slugify.convert('Ƣƣ')
|
43
|
+
assert_equal 'uuuzzzqq', Slugify.convert('ưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ')
|
44
|
+
assert_equal '', Slugify.convert('ƳƴƸƹƺƻƾƿ')
|
45
|
+
assert_equal 'dzdzdzljljljnjnjnjaai', Slugify.convert('ǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏ')
|
46
|
+
assert_equal '', Slugify.convert('ǀǁǂǃ')
|
47
|
+
assert_equal 'ioouuuuuuuuuueaa', Slugify.convert('ǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟ')
|
48
|
+
assert_equal 'aaaeaeggggkkoooo', Slugify.convert('ǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯ')
|
49
|
+
assert_equal '', Slugify.convert('ǮǯǶǷȜȝȡȢȣȴȵȶ')
|
50
|
+
assert_equal 'jdzdzdzggnnaaaeaeoo', Slugify.convert('ǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ')
|
51
|
+
assert_equal 'aaaaeeeeiiiioooo', Slugify.convert('ȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏ')
|
52
|
+
assert_equal 'rrrruuuusstthh', Slugify.convert('ȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ')
|
53
|
+
assert_equal 'nzzaaeeoooooo', Slugify.convert('ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯ')
|
54
|
+
assert_equal 'ooyyjdbqpacclls', Slugify.convert('ȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ')
|
55
|
+
assert_equal 'zbuveejjqqrryy', Slugify.convert('ɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏ')
|
56
|
+
assert_equal '', Slugify.convert('Ɂɂɒɓɔɕɖɘəɚɛɜɝɞɟɣɤɥɦɧɪɫɬɭɮ')
|
57
|
+
assert_equal 'ad', Slugify.convert('ɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟ')
|
58
|
+
assert_equal 'gggw', Slugify.convert('ɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ')
|
59
|
+
assert_equal 'mooe', Slugify.convert('ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ')
|
60
|
+
assert_equal '', Slugify.convert('ɰɳɴɷɸɹɺɻɼɽɾɿᴈ')
|
61
|
+
assert_equal 'aaeaebcddejklmno', Slugify.convert('ᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏ')
|
62
|
+
assert_equal 'aabbbbbbccdddddd', Slugify.convert('ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏ')
|
63
|
+
assert_equal 'ddddeeeeeeeeeeff', Slugify.convert('ḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟ')
|
64
|
+
assert_equal 'gghhhhhhhhhhiiii', Slugify.convert('ḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯ')
|
65
|
+
assert_equal 'kkkkkkllllllllmm', Slugify.convert('ḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿ')
|
66
|
+
assert_equal 'mmmmnnnnnnnnoooo', Slugify.convert('ṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏ')
|
67
|
+
assert_equal 'oooopppprrrrrrrr', Slugify.convert('ṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟ')
|
68
|
+
assert_equal 'sssssssssstttttt', Slugify.convert('ṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯ')
|
69
|
+
assert_equal 'ttuuuuuuuuuuvvvv', Slugify.convert('ṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿ')
|
70
|
+
assert_equal 'wwwwwwwwwwxxxxyy', Slugify.convert('ẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏ')
|
71
|
+
assert_equal 'zzzzzzhtwya', Slugify.convert('ẐẑẒẓẔẕẖẗẘẙẚẛẞẟ')
|
72
|
+
assert_equal '', Slugify.convert('ẛẞẟỈỉỊịₔℇ℈ℐℑℒℓ℔℣℥Ω℧ℨ℩ℭ')
|
73
|
+
assert_equal 'aaaaaaaaaaaaaaaa', Slugify.convert('ẠạẢảẤấẦầẨẩẪẫẬậẮắ')
|
74
|
+
assert_equal 'aaaaaaaaeeeeeeee', Slugify.convert('ẰằẲẳẴẵẶặẸẹẺẻẼẽẾế')
|
75
|
+
assert_equal 'eeeeeeeeoooo', Slugify.convert('ỀềỂểỄễỆệỌọỎỏ')
|
76
|
+
assert_equal 'oooooooooooooooo', Slugify.convert('ỐốỒồỔổỖỗỘộỚớỜờỞở')
|
77
|
+
assert_equal 'oooouuuuuuuuuuuu', Slugify.convert('ỠỡỢợỤụỦủỨứỪừỬửỮữ')
|
78
|
+
assert_equal 'uuyyyyyyyy', Slugify.convert('ỰựỲỳỴỵỶỷỸỹ')
|
79
|
+
assert_equal 'aeox', Slugify.convert('ₐₑₒₓₔ')
|
80
|
+
assert_equal 'acasccccocufghhhhh', Slugify.convert('℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏ')
|
81
|
+
assert_equal 'nppqrrrpxr', Slugify.convert('ℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟')
|
82
|
+
assert_equal 'smteltmzkabee', Slugify.convert('℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯ')
|
83
|
+
assert_equal '91011121314151617181920abcd', Slugify.convert('⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟')
|
84
|
+
assert_equal 'efghijklmnopqrst', Slugify.convert('⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯')
|
85
|
+
assert_equal 'uvwxyzabcdefghij', Slugify.convert('⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿ')
|
86
|
+
assert_equal 'klmnopqrstuvwxyz', Slugify.convert('ⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ')
|
87
|
+
assert_equal 'abcdefghijklmnop', Slugify.convert('ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟ')
|
88
|
+
assert_equal 'qrstuvwxyz0', Slugify.convert('ⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪')
|
89
|
+
assert_equal 'fsaaaaaoaoajajavavafafafaf', Slugify.convert('ꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿ')
|
90
|
+
assert_equal 'abcdefghijklmno', Slugify.convert('@ABCDEFGHIJKLMNO')
|
91
|
+
assert_equal 'pqrstuvwxyz-', Slugify.convert('PQRSTUVWXYZ[\]^_')
|
92
|
+
assert_equal '', Slugify.convert('[\]^{|}')
|
93
|
+
assert_equal 'abcdefghijklmno', Slugify.convert('`abcdefghijklmno')
|
94
|
+
assert_equal 'pqrstuvwxyz-', Slugify.convert('pqrstuvwxyz{|}~')
|
95
|
+
|
96
|
+
assert_equal 'abvgdklmnzh', Slugify.convert('АБВГДклмнж')
|
97
|
+
|
98
|
+
assert_equal 'abcdefghijklmnopqrstuvwxyz', Slugify.convert('abcdefghijklmnopqrstuvwxyz')
|
99
|
+
assert_equal 'abcdefghijklmnopqrstuvwxyz', Slugify.convert('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
100
|
+
assert_equal '0123456789', Slugify.convert('0123456789')
|
101
|
+
assert_equal '23', Slugify.convert('²³')
|
102
|
+
assert_equal '------------------', Slugify.convert('({})-_[],.;:=~+<>&')
|
103
|
+
assert_equal '', Slugify.convert('|@"#§^!°*$%£`?/\\')
|
104
|
+
assert_equal 'uu', Slugify.convert('ùµ')
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_slugify_trim
|
108
|
+
assert_equal '', Slugify.convert('--', true)
|
109
|
+
assert_equal 'test', Slugify.convert('-test', true)
|
110
|
+
assert_equal 'test', Slugify.convert('test-', true)
|
111
|
+
assert_equal 'test', Slugify.convert('-test-', true)
|
112
|
+
assert_equal 'test-test', Slugify.convert('-test-test-', true)
|
113
|
+
assert_equal 'test-test', Slugify.convert('-test--test-', true)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Encoding: utf-8
|
2
|
+
require 'test/unit'
|
3
|
+
require File.dirname(__FILE__) + "/../lib/slugify"
|
4
|
+
|
5
|
+
class StringSlugifyTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_slugify
|
8
|
+
assert_nothing_raised do
|
9
|
+
assert_equal "dummy", "dummy".slugify
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_equal 'test-test', 'tést test'.slugify
|
13
|
+
assert_equal 'test--test', 'test test'.slugify
|
14
|
+
assert_equal 'test-test', 'test test'.slugify(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_slugify_trim
|
18
|
+
assert_nothing_raised do
|
19
|
+
assert_equal 'test-test', 'test test'.slugify_trim
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
### 0.6.5 / 2017-01-22
|
2
|
+
|
3
|
+
* Provide a pure-Ruby fallback for the native unmasking code
|
4
|
+
|
5
|
+
### 0.6.4 / 2016-05-20
|
6
|
+
|
7
|
+
* Amend warnings issued when running with -W2
|
8
|
+
* Make sure message strings passed in by the app are transcoded to UTF-8
|
9
|
+
* Copy strings if necessary for frozen-string compatibility
|
10
|
+
|
11
|
+
### 0.6.3 / 2015-11-06
|
12
|
+
|
13
|
+
* Reject draft-76 handshakes if their Sec-WebSocket-Key headers are invalid
|
14
|
+
* Throw a more helpful error if a client is created with an invalid URL
|
15
|
+
|
16
|
+
### 0.6.2 / 2015-07-18
|
17
|
+
|
18
|
+
* When the peer sends a close frame with no error code, emit 1000
|
19
|
+
|
20
|
+
### 0.6.1 / 2015-07-13
|
21
|
+
|
22
|
+
* Fix how events are stored in `EventEmitter` to fix a backward-compatibility
|
23
|
+
violation introduced in the last release
|
24
|
+
* Use the `Array#pack` and `String#unpack` methods for reading/writing numbers
|
25
|
+
to buffers rather than including duplicate logic for this
|
26
|
+
|
27
|
+
### 0.6.0 / 2015-07-08
|
28
|
+
|
29
|
+
* Use `SecureRandom` to generate the `Sec-WebSocket-Key` header
|
30
|
+
* Allow the parser to recover cleanly if event listeners raise an error
|
31
|
+
* Let the `on()` method take a lambda as a positional argument rather than a block
|
32
|
+
* Add a `pong` method for sending unsolicited pong frames
|
33
|
+
|
34
|
+
### 0.5.4 / 2015-03-29
|
35
|
+
|
36
|
+
* Don't emit extra close frames if we receive a close frame after we already
|
37
|
+
sent one
|
38
|
+
* Fail the connection when the driver receives an invalid
|
39
|
+
`Sec-WebSocket-Extensions` header
|
40
|
+
|
41
|
+
### 0.5.3 / 2015-02-22
|
42
|
+
|
43
|
+
* Don't treat incoming data as WebSocket frames if a client driver is closed
|
44
|
+
before receiving the server handshake
|
45
|
+
|
46
|
+
### 0.5.2 / 2015-02-19
|
47
|
+
|
48
|
+
* Don't emit multiple `error` events
|
49
|
+
|
50
|
+
### 0.5.1 / 2014-12-18
|
51
|
+
|
52
|
+
* Don't allow drivers to be created with unrecognized options
|
53
|
+
|
54
|
+
### 0.5.0 / 2014-12-13
|
55
|
+
|
56
|
+
* Support protocol extensions via the websocket-extensions module
|
57
|
+
|
58
|
+
### 0.4.0 / 2014-11-08
|
59
|
+
|
60
|
+
* Support connection via HTTP proxies using `CONNECT`
|
61
|
+
|
62
|
+
### 0.3.5 / 2014-10-04
|
63
|
+
|
64
|
+
* Fix bug where the `Server` driver doesn't pass `ping` callbacks to its
|
65
|
+
delegate
|
66
|
+
* Fix an arity error when calling `fail_request`
|
67
|
+
* Allow `close` to be called before `start` to close the driver
|
68
|
+
|
69
|
+
### 0.3.4 / 2014-07-06
|
70
|
+
|
71
|
+
* Don't hold references to frame buffers after a message has been emitted
|
72
|
+
* Make sure that `protocol` and `version` are exposed properly by the TCP driver
|
73
|
+
* Correct HTTP header parsing based on RFC 7230; header names cannot contain
|
74
|
+
backslashes
|
75
|
+
|
76
|
+
### 0.3.3 / 2014-04-24
|
77
|
+
|
78
|
+
* Fix problems with loading C and Java native extension code
|
79
|
+
* Correct the acceptable characters used in the HTTP parser
|
80
|
+
* Correct the draft-76 status line reason phrase
|
81
|
+
|
82
|
+
### 0.3.2 / 2013-12-29
|
83
|
+
|
84
|
+
* Expand `max_length` to cover sequences of continuation frames and
|
85
|
+
`draft-{75,76}`
|
86
|
+
* Decrease default maximum frame buffer size to 64MB
|
87
|
+
* Stop parsing when the protocol enters a failure mode, to save CPU cycles
|
88
|
+
|
89
|
+
### 0.3.1 / 2013-12-03
|
90
|
+
|
91
|
+
* Add a `max_length` option to limit allowed frame size
|
92
|
+
|
93
|
+
### 0.3.0 / 2013-09-09
|
94
|
+
|
95
|
+
* Support client URLs with Basic Auth credentials
|
96
|
+
|
97
|
+
### 0.2.3 / 2013-08-04
|
98
|
+
|
99
|
+
* Fix bug in EventEmitter#emit when listeners are removed
|
100
|
+
|
101
|
+
### 0.2.2 / 2013-08-04
|
102
|
+
|
103
|
+
* Fix bug in EventEmitter#listener_count for unregistered events
|
104
|
+
|
105
|
+
### 0.2.1 / 2013-07-05
|
106
|
+
|
107
|
+
* Queue sent messages if the client has not begun trying to connect
|
108
|
+
* Encode all strings sent to I/O as `ASCII-8BIT`
|
109
|
+
|
110
|
+
### 0.2.0 / 2013-05-12
|
111
|
+
|
112
|
+
* Add API for setting and reading headers
|
113
|
+
* Add Driver.server() method for getting a driver for TCP servers
|
114
|
+
|
115
|
+
### 0.1.0 / 2013-05-04
|
116
|
+
|
117
|
+
* First stable release
|
118
|
+
|
119
|
+
### 0.0.0 / 2013-04-22
|
120
|
+
|
121
|
+
* First release
|
122
|
+
* Proof of concept for people to try out
|
123
|
+
* Might be unstable
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# License
|
2
|
+
|
3
|
+
(The MIT License)
|
4
|
+
|
5
|
+
Copyright (c) 2010-2017 James Coglan
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
8
|
+
this software and associated documentation files (the 'Software'), to deal in
|
9
|
+
the Software without restriction, including without limitation the rights to
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
11
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
12
|
+
subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
19
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
20
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
21
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
22
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,369 @@
|
|
1
|
+
# websocket-driver [![Build Status](https://travis-ci.org/faye/websocket-driver-ruby.svg)](https://travis-ci.org/faye/websocket-driver-ruby)
|
2
|
+
|
3
|
+
This module provides a complete implementation of the WebSocket protocols that
|
4
|
+
can be hooked up to any TCP library. It aims to simplify things by decoupling
|
5
|
+
the protocol details from the I/O layer, such that users only need to implement
|
6
|
+
code to stream data in and out of it without needing to know anything about how
|
7
|
+
the protocol actually works. Think of it as a complete WebSocket system with
|
8
|
+
pluggable I/O.
|
9
|
+
|
10
|
+
Due to this design, you get a lot of things for free. In particular, if you hook
|
11
|
+
this module up to some I/O object, it will do all of this for you:
|
12
|
+
|
13
|
+
* Select the correct server-side driver to talk to the client
|
14
|
+
* Generate and send both server- and client-side handshakes
|
15
|
+
* Recognize when the handshake phase completes and the WS protocol begins
|
16
|
+
* Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`
|
17
|
+
* Negotiate and use extensions via the
|
18
|
+
[websocket-extensions](https://github.com/faye/websocket-extensions-ruby)
|
19
|
+
module
|
20
|
+
* Buffer sent messages until the handshake process is finished
|
21
|
+
* Deal with proxies that defer delivery of the draft-76 handshake body
|
22
|
+
* Notify you when the socket is open and closed and when messages arrive
|
23
|
+
* Recombine fragmented messages
|
24
|
+
* Dispatch text, binary, ping, pong and close frames
|
25
|
+
* Manage the socket-closing handshake process
|
26
|
+
* Automatically reply to ping frames with a matching pong
|
27
|
+
* Apply masking to messages sent by the client
|
28
|
+
|
29
|
+
This library was originally extracted from the [Faye](http://faye.jcoglan.com)
|
30
|
+
project but now aims to provide simple WebSocket support for any Ruby server or
|
31
|
+
I/O system.
|
32
|
+
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
```
|
37
|
+
$ gem install websocket-driver
|
38
|
+
```
|
39
|
+
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
To build either a server-side or client-side socket, the only requirement is
|
44
|
+
that you supply a `socket` object with these methods:
|
45
|
+
|
46
|
+
* `socket.url` - returns the full URL of the socket as a string.
|
47
|
+
* `socket.write(string)` - writes the given string to a TCP stream.
|
48
|
+
|
49
|
+
Server-side sockets require one additional method:
|
50
|
+
|
51
|
+
* `socket.env` - returns a Rack-style env hash that will contain some of the
|
52
|
+
following fields. Their values are strings containing the value of the named
|
53
|
+
header, unless stated otherwise.
|
54
|
+
* `HTTP_CONNECTION`
|
55
|
+
* `HTTP_HOST`
|
56
|
+
* `HTTP_ORIGIN`
|
57
|
+
* `HTTP_SEC_WEBSOCKET_EXTENSIONS`
|
58
|
+
* `HTTP_SEC_WEBSOCKET_KEY`
|
59
|
+
* `HTTP_SEC_WEBSOCKET_KEY1`
|
60
|
+
* `HTTP_SEC_WEBSOCKET_KEY2`
|
61
|
+
* `HTTP_SEC_WEBSOCKET_PROTOCOL`
|
62
|
+
* `HTTP_SEC_WEBSOCKET_VERSION`
|
63
|
+
* `HTTP_UPGRADE`
|
64
|
+
* `rack.input`, an `IO` object representing the request body
|
65
|
+
* `REQUEST_METHOD`, the request's HTTP verb
|
66
|
+
|
67
|
+
|
68
|
+
### Server-side with Rack
|
69
|
+
|
70
|
+
To handle a server-side WebSocket connection, you need to check whether the
|
71
|
+
request is a WebSocket handshake, and if so create a protocol driver for it.
|
72
|
+
You must give the driver an object with the `env`, `url` and `write` methods. A
|
73
|
+
simple example might be:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
require 'websocket/driver'
|
77
|
+
require 'eventmachine'
|
78
|
+
|
79
|
+
class WS
|
80
|
+
attr_reader :env, :url
|
81
|
+
|
82
|
+
def initialize(env)
|
83
|
+
@env = env
|
84
|
+
|
85
|
+
secure = Rack::Request.new(env).ssl?
|
86
|
+
scheme = secure ? 'wss:' : 'ws:'
|
87
|
+
@url = scheme + '//' + env['HTTP_HOST'] + env['REQUEST_URI']
|
88
|
+
|
89
|
+
@driver = WebSocket::Driver.rack(self)
|
90
|
+
|
91
|
+
env['rack.hijack'].call
|
92
|
+
@io = env['rack.hijack_io']
|
93
|
+
|
94
|
+
EM.attach(@io, Reader) { |conn| conn.driver = @driver }
|
95
|
+
|
96
|
+
@driver.start
|
97
|
+
end
|
98
|
+
|
99
|
+
def write(string)
|
100
|
+
@io.write(string)
|
101
|
+
end
|
102
|
+
|
103
|
+
module Reader
|
104
|
+
attr_writer :driver
|
105
|
+
|
106
|
+
def receive_data(string)
|
107
|
+
@driver.parse(string)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
To explain what's going on here: the `WS` class implements the `env`, `url` and
|
114
|
+
`write(string)` methods as required. When instantiated with a Rack environment,
|
115
|
+
it stores the environment and infers the complete URL from it. Having set up
|
116
|
+
the `env` and `url`, it asks `WebSocket::Driver` for a server-side driver for
|
117
|
+
the socket. Then it uses the Rack hijack API to gain access to the TCP stream,
|
118
|
+
and uses EventMachine to stream in incoming data from the client, handing
|
119
|
+
incoming data off to the driver for parsing. Finally, we tell the driver to
|
120
|
+
`start`, which will begin sending the handshake response. This will invoke the
|
121
|
+
`WS#write` method, which will send the response out over the TCP socket.
|
122
|
+
|
123
|
+
Having defined this class we could use it like this when handling a request:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
if WebSocket::Driver.websocket?(env)
|
127
|
+
socket = WS.new(env)
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
The driver API is described in full below.
|
132
|
+
|
133
|
+
|
134
|
+
### Server-side with TCP
|
135
|
+
|
136
|
+
You can also handle WebSocket connections in a bare TCP server, if you're not
|
137
|
+
using Rack and don't want to implement HTTP parsing yourself. For this, your
|
138
|
+
socket object only needs a `write` method.
|
139
|
+
|
140
|
+
The driver will emit a `:connect` event when a request is received, and at this
|
141
|
+
point you can detect whether it's a WebSocket and handle it as such. Here's an
|
142
|
+
example using an EventMachine TCP server.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
module Connection
|
146
|
+
def initialize
|
147
|
+
@driver = WebSocket::Driver.server(self)
|
148
|
+
|
149
|
+
@driver.on :connect, -> (event) do
|
150
|
+
if WebSocket::Driver.websocket?(@driver.env)
|
151
|
+
@driver.start
|
152
|
+
else
|
153
|
+
# handle other HTTP requests
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
@driver.on :message, -> (e) { @driver.text(e.data) }
|
158
|
+
@driver.on :close, -> (e) { close_connection_after_writing }
|
159
|
+
end
|
160
|
+
|
161
|
+
def receive_data(data)
|
162
|
+
@driver.parse(data)
|
163
|
+
end
|
164
|
+
|
165
|
+
def write(data)
|
166
|
+
send_data(data)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
EM.run {
|
171
|
+
EM.start_server('127.0.0.1', 4180, Connection)
|
172
|
+
}
|
173
|
+
```
|
174
|
+
|
175
|
+
In the `:connect` event, `@driver.env` is a Rack env representing the request.
|
176
|
+
If the request has a body, it will be in the `@driver.env['rack.input']` stream,
|
177
|
+
but only as much of the body as you have so far routed to it using the `parse`
|
178
|
+
method.
|
179
|
+
|
180
|
+
|
181
|
+
### Client-side
|
182
|
+
|
183
|
+
Similarly, to implement a WebSocket client you need an object with `url` and
|
184
|
+
`write` methods. Once you have one such object, you ask for a driver for it:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
driver = WebSocket::Driver.client(socket)
|
188
|
+
```
|
189
|
+
|
190
|
+
After this you use the driver API as described below to process incoming data
|
191
|
+
and send outgoing data.
|
192
|
+
|
193
|
+
Client drivers have two additional methods for reading the HTTP data that was
|
194
|
+
sent back by the server:
|
195
|
+
|
196
|
+
* `driver.status` - the integer value of the HTTP status code
|
197
|
+
* `driver.headers` - a hash-like object containing the response headers
|
198
|
+
|
199
|
+
|
200
|
+
### HTTP Proxies
|
201
|
+
|
202
|
+
The client driver supports connections via HTTP proxies using the `CONNECT`
|
203
|
+
method. Instead of sending the WebSocket handshake immediately, it will send a
|
204
|
+
`CONNECT` request, wait for a `200` response, and then proceed as normal.
|
205
|
+
|
206
|
+
To use this feature, call `proxy = driver.proxy(url)` where `url` is the origin
|
207
|
+
of the proxy, including a username and password if required. This produces an
|
208
|
+
object that manages the process of connecting via the proxy. You should call
|
209
|
+
`proxy.start` to begin the connection process, and pass data you receive via the
|
210
|
+
socket to `proxy.parse(data)`. When the proxy emits `:connect`, you should then
|
211
|
+
start sending incoming data to `driver.parse(data)` as normal, and call
|
212
|
+
`driver.start`.
|
213
|
+
|
214
|
+
```rb
|
215
|
+
proxy = driver.proxy('http://username:password@proxy.example.com')
|
216
|
+
|
217
|
+
proxy.on :connect, -> (event) do
|
218
|
+
driver.start
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
The proxy's `:connect` event is also where you should perform a TLS handshake on
|
223
|
+
your TCP stream, if you are connecting to a `wss:` endpoint.
|
224
|
+
|
225
|
+
In the event that proxy connection fails, `proxy` will emit an `:error`. You can
|
226
|
+
inspect the proxy's response via `proxy.status` and `proxy.headers`.
|
227
|
+
|
228
|
+
```rb
|
229
|
+
proxy.on :error, -> (error) do
|
230
|
+
puts error.message
|
231
|
+
puts proxy.status
|
232
|
+
puts proxy.headers.inspect
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
236
|
+
Before calling `proxy.start` you can set custom headers using
|
237
|
+
`proxy.set_header`:
|
238
|
+
|
239
|
+
```rb
|
240
|
+
proxy.set_header('User-Agent', 'ruby')
|
241
|
+
proxy.start
|
242
|
+
```
|
243
|
+
|
244
|
+
|
245
|
+
### Driver API
|
246
|
+
|
247
|
+
Drivers are created using one of the following methods:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
driver = WebSocket::Driver.rack(socket, options)
|
251
|
+
driver = WebSocket::Driver.server(socket, options)
|
252
|
+
driver = WebSocket::Driver.client(socket, options)
|
253
|
+
```
|
254
|
+
|
255
|
+
The `rack` method returns a driver chosen using the socket's `env`. The `server`
|
256
|
+
method returns a driver that will parse an HTTP request and then decide which
|
257
|
+
driver to use for it using the `rack` method. The `client` method always returns
|
258
|
+
a driver for the RFC version of the protocol with masking enabled on outgoing
|
259
|
+
frames.
|
260
|
+
|
261
|
+
The `options` argument is optional, and is a hash. It may contain the following
|
262
|
+
keys:
|
263
|
+
|
264
|
+
* `:max_length` - the maximum allowed size of incoming message frames, in bytes.
|
265
|
+
The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
|
266
|
+
* `:protocols` - an array of strings representing acceptable subprotocols for
|
267
|
+
use over the socket. The driver will negotiate one of these to use via the
|
268
|
+
`Sec-WebSocket-Protocol` header if supported by the other peer.
|
269
|
+
|
270
|
+
All drivers respond to the following API methods, but some of them are no-ops
|
271
|
+
depending on whether the client supports the behaviour.
|
272
|
+
|
273
|
+
Note that most of these methods are commands: if they produce data that should
|
274
|
+
be sent over the socket, they will give this to you by calling
|
275
|
+
`socket.write(string)`.
|
276
|
+
|
277
|
+
#### `driver.on :open, -> (event) { }`
|
278
|
+
|
279
|
+
Adds a callback block to execute when the socket becomes open.
|
280
|
+
|
281
|
+
#### `driver.on :message, -> (event) { }`
|
282
|
+
|
283
|
+
Adds a callback block to execute when a message is received. `event` will have a
|
284
|
+
`data` attribute containing either a string in the case of a text message or an
|
285
|
+
array of integers in the case of a binary message.
|
286
|
+
|
287
|
+
#### `driver.on :error, -> (event) { }`
|
288
|
+
|
289
|
+
Adds a callback to execute when a protocol error occurs due to the other peer
|
290
|
+
sending an invalid byte sequence. `event` will have a `message` attribute
|
291
|
+
describing the error.
|
292
|
+
|
293
|
+
#### `driver.on :close, -> (event) { }`
|
294
|
+
|
295
|
+
Adds a callback block to execute when the socket becomes closed. The `event`
|
296
|
+
object has `code` and `reason` attributes.
|
297
|
+
|
298
|
+
#### `driver.add_extension(extension)`
|
299
|
+
|
300
|
+
Registers a protocol extension whose operation will be negotiated via the
|
301
|
+
`Sec-WebSocket-Extensions` header. `extension` is any extension compatible with
|
302
|
+
the [websocket-extensions](https://github.com/faye/websocket-extensions-ruby)
|
303
|
+
framework.
|
304
|
+
|
305
|
+
#### `driver.set_header(name, value)`
|
306
|
+
|
307
|
+
Sets a custom header to be sent as part of the handshake response, either from
|
308
|
+
the server or from the client. Must be called before `start`, since this is when
|
309
|
+
the headers are serialized and sent.
|
310
|
+
|
311
|
+
#### `driver.start`
|
312
|
+
|
313
|
+
Initiates the protocol by sending the handshake - either the response for a
|
314
|
+
server-side driver or the request for a client-side one. This should be the
|
315
|
+
first method you invoke. Returns `true` if and only if a handshake was sent.
|
316
|
+
|
317
|
+
#### `driver.parse(string)`
|
318
|
+
|
319
|
+
Takes a string and parses it, potentially resulting in message events being
|
320
|
+
emitted (see `on('message')` above) or in data being sent to `socket.write`.
|
321
|
+
You should send all data you receive via I/O to this method.
|
322
|
+
|
323
|
+
#### `driver.text(string)`
|
324
|
+
|
325
|
+
Sends a text message over the socket. If the socket handshake is not yet
|
326
|
+
complete, the message will be queued until it is. Returns `true` if the message
|
327
|
+
was sent or queued, and `false` if the socket can no longer send messages.
|
328
|
+
|
329
|
+
#### `driver.binary(array)`
|
330
|
+
|
331
|
+
Takes an array of byte-sized integers and sends them as a binary message. Will
|
332
|
+
queue and return `true` or `false` the same way as the `text` method. It will
|
333
|
+
also return `false` if the driver does not support binary messages.
|
334
|
+
|
335
|
+
#### `driver.ping(string = '', &callback)`
|
336
|
+
|
337
|
+
Sends a ping frame over the socket, queueing it if necessary. `string` and the
|
338
|
+
`callback` block are both optional. If a callback is given, it will be invoked
|
339
|
+
when the socket receives a pong frame whose content matches `string`. Returns
|
340
|
+
`false` if frames can no longer be sent, or if the driver does not support
|
341
|
+
ping/pong.
|
342
|
+
|
343
|
+
#### `driver.pong(string = '')`
|
344
|
+
|
345
|
+
Sends a pong frame over the socket, queueing it if necessary. `string` is
|
346
|
+
optional. Returns `false` if frames can no longer be sent, or if the driver does
|
347
|
+
not support ping/pong.
|
348
|
+
|
349
|
+
You don't need to call this when a ping frame is received; pings are replied to
|
350
|
+
automatically by the driver. This method is for sending unsolicited pongs.
|
351
|
+
|
352
|
+
#### `driver.close`
|
353
|
+
|
354
|
+
Initiates the closing handshake if the socket is still open. For drivers with no
|
355
|
+
closing handshake, this will result in the immediate execution of the
|
356
|
+
`on('close')` callback. For drivers with a closing handshake, this sends a
|
357
|
+
closing frame and `emit('close')` will execute when a response is received or a
|
358
|
+
protocol error occurs.
|
359
|
+
|
360
|
+
#### `driver.version`
|
361
|
+
|
362
|
+
Returns the WebSocket version in use as a string. Will either be `hixie-75`,
|
363
|
+
`hixie-76` or `hybi-$version`.
|
364
|
+
|
365
|
+
#### `driver.protocol`
|
366
|
+
|
367
|
+
Returns a string containing the selected subprotocol, if any was agreed upon
|
368
|
+
using the `Sec-WebSocket-Protocol` mechanism. This value becomes available after
|
369
|
+
`emit('open')` has fired.
|