p2p_streams_channel 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/README.md +210 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/javascripts/p2p/index.js +6 -0
  6. data/app/assets/javascripts/p2p/message.js +22 -0
  7. data/app/assets/javascripts/p2p/p2p_connection.js +133 -0
  8. data/app/assets/javascripts/p2p/p2p_controller.js +52 -0
  9. data/app/assets/javascripts/p2p/p2p_frame.js +152 -0
  10. data/app/assets/javascripts/p2p/p2p_peer.js +208 -0
  11. data/app/assets/javascripts/p2p/package.json +14 -0
  12. data/app/channels/signaling_channel.rb +29 -0
  13. data/app/helpers/p2p_streams_channel/tag_helper.rb +16 -0
  14. data/lib/p2p_streams_channel/cache.rb +22 -0
  15. data/lib/p2p_streams_channel/engine.rb +20 -0
  16. data/lib/p2p_streams_channel/negotiation.rb +25 -0
  17. data/lib/p2p_streams_channel/session.rb +57 -0
  18. data/lib/p2p_streams_channel/session_handler.rb +32 -0
  19. data/lib/p2p_streams_channel/session_state.rb +33 -0
  20. data/lib/p2p_streams_channel/version.rb +5 -0
  21. data/lib/p2p_streams_channel.rb +29 -0
  22. data/lib/rails/generators/p2p_streams_channel/controller_generator.rb +12 -0
  23. data/lib/rails/generators/p2p_streams_channel/install_generator.rb +24 -0
  24. data/lib/rails/generators/p2p_streams_channel/templates/controller.js +51 -0
  25. data/lib/rails/generators/p2p_streams_channel/templates/initializer.rb +4 -0
  26. data/p2p_streams_channel.gemspec +38 -0
  27. data/sig/p2p_streams_channel.rbs +4 -0
  28. data/spec/dummy/Rakefile +6 -0
  29. data/spec/dummy/app/assets/config/manifest.js +4 -0
  30. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  31. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  32. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  34. data/spec/dummy/app/controllers/p2p_controller.rb +7 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy/app/helpers/p2p_helper.rb +2 -0
  37. data/spec/dummy/app/javascript/application.js +4 -0
  38. data/spec/dummy/app/javascript/controllers/application.js +9 -0
  39. data/spec/dummy/app/javascript/controllers/chat_controller.js +46 -0
  40. data/spec/dummy/app/javascript/controllers/index.js +11 -0
  41. data/spec/dummy/app/jobs/application_job.rb +7 -0
  42. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  43. data/spec/dummy/app/models/application_record.rb +3 -0
  44. data/spec/dummy/app/views/layouts/application.html.erb +16 -0
  45. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  46. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  47. data/spec/dummy/app/views/p2p/index.html.erb +6 -0
  48. data/spec/dummy/app/views/p2p/room_chat.html.erb +19 -0
  49. data/spec/dummy/bin/importmap +4 -0
  50. data/spec/dummy/bin/rails +4 -0
  51. data/spec/dummy/bin/rake +4 -0
  52. data/spec/dummy/bin/setup +33 -0
  53. data/spec/dummy/config/application.rb +22 -0
  54. data/spec/dummy/config/boot.rb +5 -0
  55. data/spec/dummy/config/cable.yml +12 -0
  56. data/spec/dummy/config/database.yml +25 -0
  57. data/spec/dummy/config/environment.rb +5 -0
  58. data/spec/dummy/config/environments/development.rb +68 -0
  59. data/spec/dummy/config/environments/production.rb +87 -0
  60. data/spec/dummy/config/environments/test.rb +60 -0
  61. data/spec/dummy/config/importmap.rb +7 -0
  62. data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
  63. data/spec/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  64. data/spec/dummy/config/initializers/inflections.rb +16 -0
  65. data/spec/dummy/config/initializers/p2p_streams_channel.rb +4 -0
  66. data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
  67. data/spec/dummy/config/locales/en.yml +33 -0
  68. data/spec/dummy/config/puma.rb +43 -0
  69. data/spec/dummy/config/routes.rb +4 -0
  70. data/spec/dummy/config/storage.yml +34 -0
  71. data/spec/dummy/config.ru +6 -0
  72. data/spec/dummy/db/test.sqlite3 +0 -0
  73. data/spec/dummy/log/test.log +0 -0
  74. data/spec/dummy/public/404.html +67 -0
  75. data/spec/dummy/public/422.html +67 -0
  76. data/spec/dummy/public/500.html +66 -0
  77. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  78. data/spec/dummy/public/apple-touch-icon.png +0 -0
  79. data/spec/dummy/public/favicon.ico +0 -0
  80. data/spec/dummy/tmp/development_secret.txt +1 -0
  81. data/spec/p2p_peer_status_spec.rb +89 -0
  82. data/spec/p2p_send_data_spec.rb +52 -0
  83. data/spec/p2p_streams_channel_spec.rb +7 -0
  84. data/spec/rails_helper.rb +8 -0
  85. data/spec/session_spec.rb +29 -0
  86. data/spec/spec_helper.rb +16 -0
  87. metadata +259 -0
@@ -0,0 +1,43 @@
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers: a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum; this matches the default thread size of Active Record.
6
+ #
7
+ max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8
+ min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
9
+ threads min_threads_count, max_threads_count
10
+
11
+ # Specifies the `worker_timeout` threshold that Puma will use to wait before
12
+ # terminating a worker in development environments.
13
+ #
14
+ worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
15
+
16
+ # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
17
+ #
18
+ port ENV.fetch("PORT") { 3000 }
19
+
20
+ # Specifies the `environment` that Puma will run in.
21
+ #
22
+ environment ENV.fetch("RAILS_ENV") { "development" }
23
+
24
+ # Specifies the `pidfile` that Puma will use.
25
+ pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
26
+
27
+ # Specifies the number of `workers` to boot in clustered mode.
28
+ # Workers are forked web server processes. If using threads and workers together
29
+ # the concurrency of the application would be max `threads` * `workers`.
30
+ # Workers do not work on JRuby or Windows (both of which do not support
31
+ # processes).
32
+ #
33
+ # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
34
+
35
+ # Use the `preload_app!` method when specifying a `workers` number.
36
+ # This directive tells Puma to first boot the application and load code
37
+ # before forking the application. This takes advantage of Copy On Write
38
+ # process behavior so workers use less memory.
39
+ #
40
+ # preload_app!
41
+
42
+ # Allow puma to be restarted by `bin/rails restart` command.
43
+ plugin :tmp_restart
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ root 'p2p#index'
3
+ post '/chat', to: 'p2p#room_chat', as: :join_room_chat
4
+ end
@@ -0,0 +1,34 @@
1
+ test:
2
+ service: Disk
3
+ root: <%= Rails.root.join("tmp/storage") %>
4
+
5
+ local:
6
+ service: Disk
7
+ root: <%= Rails.root.join("storage") %>
8
+
9
+ # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10
+ # amazon:
11
+ # service: S3
12
+ # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13
+ # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14
+ # region: us-east-1
15
+ # bucket: your_own_bucket-<%= Rails.env %>
16
+
17
+ # Remember not to checkin your GCS keyfile to a repository
18
+ # google:
19
+ # service: GCS
20
+ # project: your_project
21
+ # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22
+ # bucket: your_own_bucket-<%= Rails.env %>
23
+
24
+ # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25
+ # microsoft:
26
+ # service: AzureStorage
27
+ # storage_account_name: your_account_name
28
+ # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29
+ # container: your_container_name-<%= Rails.env %>
30
+
31
+ # mirror:
32
+ # service: Mirror
33
+ # primary: local
34
+ # mirrors: [ amazon, google, microsoft ]
@@ -0,0 +1,6 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative "config/environment"
4
+
5
+ run Rails.application
6
+ Rails.application.load_server
File without changes
File without changes
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
File without changes
@@ -0,0 +1 @@
1
+ 781373b5c69e605302f610ea4cd1fa6b9de001fd8c3da090f45426becbb9d36a588b60f0dcaa8b8195f0cad362f6622ed8686633180da77065e4f1bc0988309b
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "p2p peer status", type: :system do
4
+ before do
5
+ Rails.cache.clear
6
+ end
7
+
8
+ it "should update status when new peer join" do
9
+ open_new_window
10
+ open_new_window
11
+ open_new_window
12
+
13
+ page.switch_to_window(page.windows[0])
14
+ visit "/"
15
+ find('input[placeholder="name"]').set "host"
16
+ find('input[type="submit"]').click
17
+ expect(page).to have_content("host: connected", wait: 100)
18
+
19
+ page.switch_to_window(page.windows[1])
20
+ visit "/"
21
+ find('input[placeholder="name"]').set "peer1"
22
+ find('input[type="submit"]').click
23
+ expect(page).to have_content("host: connected", wait: 100)
24
+ expect(page).to have_content("peer1: connected", wait: 100)
25
+
26
+ page.switch_to_window(page.windows[2])
27
+ visit "/"
28
+ find('input[placeholder="name"]').set "peer2"
29
+ find('input[type="submit"]').click
30
+ expect(page).to have_content("host: connected", wait: 100)
31
+ expect(page).to have_content("peer1: connected", wait: 100)
32
+ expect(page).to have_content("peer2: connected", wait: 100)
33
+ end
34
+
35
+ it "should update status when a peer disconnected" do
36
+ open_new_window
37
+ open_new_window
38
+ open_new_window
39
+
40
+ page.switch_to_window(page.windows[0])
41
+ visit "/"
42
+ find('input[placeholder="name"]').set "host"
43
+ find('input[type="submit"]').click
44
+
45
+ page.switch_to_window(page.windows[1])
46
+ visit "/"
47
+ find('input[placeholder="name"]').set "peer1"
48
+ find('input[type="submit"]').click
49
+
50
+ page.switch_to_window(page.windows[2])
51
+ visit "/"
52
+ find('input[placeholder="name"]').set "peer2"
53
+ find('input[type="submit"]').click
54
+
55
+ page.windows[1].close
56
+ expect(page).to have_content("peer1: disconnected", wait: 100)
57
+ end
58
+
59
+ it "should show streams disconnected state when host disconnected" do
60
+ open_new_window
61
+ open_new_window
62
+ open_new_window
63
+
64
+ page.switch_to_window(page.windows[1])
65
+ visit "/"
66
+ find('input[placeholder="name"]').set "host"
67
+ find('input[type="submit"]').click
68
+
69
+ page.switch_to_window(page.windows[2])
70
+ visit "/"
71
+ find('input[placeholder="name"]').set "peer1"
72
+ find('input[type="submit"]').click
73
+ expect(page).to have_content("host: connected", wait: 100)
74
+
75
+ page.switch_to_window(page.windows[3])
76
+ visit "/"
77
+ find('input[placeholder="name"]').set "peer2"
78
+ find('input[type="submit"]').click
79
+ expect(page).to have_content("host: connected", wait: 100)
80
+
81
+ page.windows[1].close
82
+
83
+ page.switch_to_window(page.windows[1])
84
+ expect(page).to have_content("Stream disconnected! please refresh to continue", wait: 100)
85
+
86
+ page.switch_to_window(page.windows[2])
87
+ expect(page).to have_content("Stream disconnected! please refresh to continue", wait: 100)
88
+ end
89
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "p2p send data", type: :system do
4
+ it "send from one peer to all peers" do
5
+ Rails.cache.clear
6
+
7
+ window1 = open_new_window
8
+ window2 = open_new_window
9
+ window3 = open_new_window
10
+
11
+ page.switch_to_window(page.windows[0])
12
+ visit "/"
13
+ find('input[placeholder="name"]').set "host"
14
+ find('input[type="submit"]').click
15
+
16
+ page.switch_to_window(page.windows[1])
17
+ visit "/"
18
+ find('input[placeholder="name"]').set "peer1"
19
+ find('input[type="submit"]').click
20
+
21
+ page.switch_to_window(page.windows[2])
22
+ visit "/"
23
+ find('input[placeholder="name"]').set "peer2"
24
+ find('input[type="submit"]').click
25
+
26
+ # send data from peer on tab 2
27
+ find('input[data-chat-target="message"]', wait: 100).set "hello"
28
+ find('input[data-action="chat#send"]').click
29
+
30
+ expect(page).to have_content("peer2: hello")
31
+
32
+ page.switch_to_window(page.windows[0])
33
+ expect(page).to have_content("peer2: hello")
34
+
35
+ page.switch_to_window(page.windows[1])
36
+ expect(page).to have_content("peer2: hello")
37
+
38
+ # send data from host peer
39
+ # test case host did not receive his message
40
+ page.switch_to_window(page.windows[0])
41
+ find('input[data-chat-target="message"]', wait: 100).set "iam host"
42
+ find('input[data-action="chat#send"]').click
43
+
44
+ expect(page).to have_content("host: iam host")
45
+
46
+ page.switch_to_window(page.windows[1])
47
+ expect(page).to have_content("host: iam host")
48
+
49
+ page.switch_to_window(page.windows[2])
50
+ expect(page).to have_content("host: iam host")
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe P2pStreamsChannel do
4
+ it "has a version number" do
5
+ expect(P2pStreamsChannel::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+ require File.expand_path("../../spec/dummy/config/environment", __FILE__)
3
+ ActiveRecord::Migrator.migrations_paths = [File.expand_path("../spec/dummy/db/migrate", __dir__)]
4
+ require 'rspec/rails'
5
+
6
+
7
+ require 'capybara/rails'
8
+ require 'capybara/rspec'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe P2pStreamsChannel::Session do
4
+ subject { P2pStreamsChannel::Session.new("test", secret_key: "123") }
5
+
6
+ it "default the first joined peer is the host" do
7
+ subject.join_peer(1)
8
+ expect(subject.session_state.host_peer_id).to be(1)
9
+ end
10
+
11
+ it "connect/disconnect peer" do
12
+ subject.join_peer(6) # host
13
+ expect(subject.session_state.peers[6]).to be(true)
14
+
15
+ subject.join_peer(15)
16
+ expect(subject.session_state.peers[15]).to be(true)
17
+ subject.disconnect_peer(15)
18
+ expect(subject.session_state.peers[15]).to be(false)
19
+ end
20
+
21
+ it "if the host peer disconnect then session should be reset" do
22
+ subject.join_peer(6)
23
+ subject.join_peer(15)
24
+
25
+ subject.disconnect_peer(6)
26
+ expect(subject.session_state.peers).to be_empty
27
+ expect(subject.session_state.host_peer_id).to be_nil
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_helper"
4
+ require "p2p_streams_channel"
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = ".rspec_status"
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+ end