hyper-operation 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +49 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +324 -0
- data/LICENSE.txt +21 -0
- data/README.md +708 -0
- data/Rakefile +4 -0
- data/examples/chat-app/.gitignore +21 -0
- data/examples/chat-app/Gemfile +57 -0
- data/examples/chat-app/Gemfile.lock +282 -0
- data/examples/chat-app/README.md +3 -0
- data/examples/chat-app/Rakefile +6 -0
- data/examples/chat-app/app/assets/config/manifest.js +3 -0
- data/examples/chat-app/app/assets/images/.keep +0 -0
- data/examples/chat-app/app/assets/javascripts/application.js +3 -0
- data/examples/chat-app/app/assets/javascripts/cable.js +13 -0
- data/examples/chat-app/app/assets/javascripts/channels/.keep +0 -0
- data/examples/chat-app/app/assets/stylesheets/application.css +15 -0
- data/examples/chat-app/app/channels/application_cable/channel.rb +4 -0
- data/examples/chat-app/app/channels/application_cable/connection.rb +4 -0
- data/examples/chat-app/app/controllers/application_controller.rb +3 -0
- data/examples/chat-app/app/controllers/concerns/.keep +0 -0
- data/examples/chat-app/app/controllers/home_controller.rb +5 -0
- data/examples/chat-app/app/helpers/application_helper.rb +2 -0
- data/examples/chat-app/app/hyperloop/components/app.rb +11 -0
- data/examples/chat-app/app/hyperloop/components/formatted_div.rb +13 -0
- data/examples/chat-app/app/hyperloop/components/input_box.rb +29 -0
- data/examples/chat-app/app/hyperloop/components/message.rb +29 -0
- data/examples/chat-app/app/hyperloop/components/messages.rb +9 -0
- data/examples/chat-app/app/hyperloop/components/nav.rb +30 -0
- data/examples/chat-app/app/hyperloop/operations/operations.rb +56 -0
- data/examples/chat-app/app/hyperloop/stores/message_store.rb +23 -0
- data/examples/chat-app/app/models/application_record.rb +3 -0
- data/examples/chat-app/app/models/concerns/.keep +0 -0
- data/examples/chat-app/app/models/models.rb +2 -0
- data/examples/chat-app/app/models/public/.keep +0 -0
- data/examples/chat-app/app/models/public/announcement.rb +8 -0
- data/examples/chat-app/app/policies/application_policy.rb +5 -0
- data/examples/chat-app/app/views/layouts/application.html.erb +51 -0
- data/examples/chat-app/bin/bundle +3 -0
- data/examples/chat-app/bin/rails +9 -0
- data/examples/chat-app/bin/rake +9 -0
- data/examples/chat-app/bin/setup +34 -0
- data/examples/chat-app/bin/spring +17 -0
- data/examples/chat-app/bin/update +29 -0
- data/examples/chat-app/config.ru +5 -0
- data/examples/chat-app/config/application.rb +13 -0
- data/examples/chat-app/config/boot.rb +3 -0
- data/examples/chat-app/config/cable.yml +9 -0
- data/examples/chat-app/config/database.yml +25 -0
- data/examples/chat-app/config/environment.rb +5 -0
- data/examples/chat-app/config/environments/development.rb +56 -0
- data/examples/chat-app/config/environments/production.rb +86 -0
- data/examples/chat-app/config/environments/test.rb +42 -0
- data/examples/chat-app/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/chat-app/config/initializers/assets.rb +11 -0
- data/examples/chat-app/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/chat-app/config/initializers/cookies_serializer.rb +5 -0
- data/examples/chat-app/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/chat-app/config/initializers/hyperloop.rb +4 -0
- data/examples/chat-app/config/initializers/inflections.rb +16 -0
- data/examples/chat-app/config/initializers/mime_types.rb +4 -0
- data/examples/chat-app/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/chat-app/config/initializers/session_store.rb +3 -0
- data/examples/chat-app/config/initializers/wrap_parameters.rb +14 -0
- data/examples/chat-app/config/locales/en.yml +23 -0
- data/examples/chat-app/config/puma.rb +47 -0
- data/examples/chat-app/config/routes.rb +5 -0
- data/examples/chat-app/config/secrets.yml +22 -0
- data/examples/chat-app/config/spring.rb +6 -0
- data/examples/chat-app/db/seeds.rb +7 -0
- data/examples/chat-app/lib/assets/.keep +0 -0
- data/examples/chat-app/lib/tasks/.keep +0 -0
- data/examples/chat-app/log/.keep +0 -0
- data/examples/chat-app/public/404.html +67 -0
- data/examples/chat-app/public/422.html +67 -0
- data/examples/chat-app/public/500.html +66 -0
- data/examples/chat-app/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/chat-app/public/apple-touch-icon.png +0 -0
- data/examples/chat-app/public/favicon.ico +0 -0
- data/examples/chat-app/public/robots.txt +5 -0
- data/examples/chat-app/test/controllers/.keep +0 -0
- data/examples/chat-app/test/fixtures/.keep +0 -0
- data/examples/chat-app/test/fixtures/files/.keep +0 -0
- data/examples/chat-app/test/helpers/.keep +0 -0
- data/examples/chat-app/test/integration/.keep +0 -0
- data/examples/chat-app/test/mailers/.keep +0 -0
- data/examples/chat-app/test/models/.keep +0 -0
- data/examples/chat-app/test/test_helper.rb +10 -0
- data/examples/chat-app/tmp/.keep +0 -0
- data/examples/chat-app/vendor/assets/javascripts/.keep +0 -0
- data/examples/chat-app/vendor/assets/stylesheets/.keep +0 -0
- data/examples/five-letter-word-game/.gitignore +21 -0
- data/examples/five-letter-word-game/Gemfile +57 -0
- data/examples/five-letter-word-game/Gemfile.lock +282 -0
- data/examples/five-letter-word-game/README.md +24 -0
- data/examples/five-letter-word-game/Rakefile +6 -0
- data/examples/five-letter-word-game/app/assets/config/manifest.js +3 -0
- data/examples/five-letter-word-game/app/assets/images/.keep +0 -0
- data/examples/five-letter-word-game/app/assets/javascripts/application.js +3 -0
- data/examples/five-letter-word-game/app/assets/javascripts/cable.js +13 -0
- data/examples/five-letter-word-game/app/assets/javascripts/channels/.keep +0 -0
- data/examples/five-letter-word-game/app/assets/stylesheets/application.css +15 -0
- data/examples/five-letter-word-game/app/channels/application_cable/channel.rb +4 -0
- data/examples/five-letter-word-game/app/channels/application_cable/connection.rb +4 -0
- data/examples/five-letter-word-game/app/controllers/application_controller.rb +14 -0
- data/examples/five-letter-word-game/app/controllers/concerns/.keep +0 -0
- data/examples/five-letter-word-game/app/controllers/home_controller.rb +5 -0
- data/examples/five-letter-word-game/app/helpers/application_helper.rb +2 -0
- data/examples/five-letter-word-game/app/hyperloop/components/app.rb +65 -0
- data/examples/five-letter-word-game/app/hyperloop/components/guesses.rb +8 -0
- data/examples/five-letter-word-game/app/hyperloop/components/input_word.rb +13 -0
- data/examples/five-letter-word-game/app/hyperloop/models/user.rb +27 -0
- data/examples/five-letter-word-game/app/hyperloop/operations/ops.rb +115 -0
- data/examples/five-letter-word-game/app/hyperloop/stores/store.rb +120 -0
- data/examples/five-letter-word-game/app/jobs/application_job.rb +2 -0
- data/examples/five-letter-word-game/app/mailers/application_mailer.rb +4 -0
- data/examples/five-letter-word-game/app/models/application_record.rb +3 -0
- data/examples/five-letter-word-game/app/models/concerns/.keep +0 -0
- data/examples/five-letter-word-game/app/policies/user_policy.rb +4 -0
- data/examples/five-letter-word-game/app/views/layouts/application.html.erb +14 -0
- data/examples/five-letter-word-game/app/views/layouts/mailer.html.erb +13 -0
- data/examples/five-letter-word-game/app/views/layouts/mailer.text.erb +1 -0
- data/examples/five-letter-word-game/bin/bundle +3 -0
- data/examples/five-letter-word-game/bin/rails +9 -0
- data/examples/five-letter-word-game/bin/rake +9 -0
- data/examples/five-letter-word-game/bin/setup +34 -0
- data/examples/five-letter-word-game/bin/spring +17 -0
- data/examples/five-letter-word-game/bin/update +29 -0
- data/examples/five-letter-word-game/config.ru +5 -0
- data/examples/five-letter-word-game/config/application.rb +12 -0
- data/examples/five-letter-word-game/config/boot.rb +3 -0
- data/examples/five-letter-word-game/config/cable.yml +9 -0
- data/examples/five-letter-word-game/config/database.yml +25 -0
- data/examples/five-letter-word-game/config/environment.rb +5 -0
- data/examples/five-letter-word-game/config/environments/development.rb +56 -0
- data/examples/five-letter-word-game/config/environments/production.rb +86 -0
- data/examples/five-letter-word-game/config/environments/test.rb +42 -0
- data/examples/five-letter-word-game/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/five-letter-word-game/config/initializers/assets.rb +11 -0
- data/examples/five-letter-word-game/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/five-letter-word-game/config/initializers/cookies_serializer.rb +5 -0
- data/examples/five-letter-word-game/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/five-letter-word-game/config/initializers/hyperloop.rb +3 -0
- data/examples/five-letter-word-game/config/initializers/inflections.rb +16 -0
- data/examples/five-letter-word-game/config/initializers/mime_types.rb +4 -0
- data/examples/five-letter-word-game/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/five-letter-word-game/config/initializers/session_store.rb +3 -0
- data/examples/five-letter-word-game/config/initializers/wrap_parameters.rb +14 -0
- data/examples/five-letter-word-game/config/locales/en.yml +23 -0
- data/examples/five-letter-word-game/config/puma.rb +47 -0
- data/examples/five-letter-word-game/config/routes.rb +5 -0
- data/examples/five-letter-word-game/config/secrets.yml +22 -0
- data/examples/five-letter-word-game/config/spring.rb +6 -0
- data/examples/five-letter-word-game/db/schema.rb +28 -0
- data/examples/five-letter-word-game/db/seeds.rb +7 -0
- data/examples/five-letter-word-game/lib/assets/.keep +0 -0
- data/examples/five-letter-word-game/lib/tasks/.keep +0 -0
- data/examples/five-letter-word-game/log/.keep +0 -0
- data/examples/five-letter-word-game/public/404.html +67 -0
- data/examples/five-letter-word-game/public/422.html +67 -0
- data/examples/five-letter-word-game/public/500.html +66 -0
- data/examples/five-letter-word-game/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/five-letter-word-game/public/apple-touch-icon.png +0 -0
- data/examples/five-letter-word-game/public/favicon.ico +0 -0
- data/examples/five-letter-word-game/public/robots.txt +5 -0
- data/examples/five-letter-word-game/test/controllers/.keep +0 -0
- data/examples/five-letter-word-game/test/fixtures/.keep +0 -0
- data/examples/five-letter-word-game/test/fixtures/files/.keep +0 -0
- data/examples/five-letter-word-game/test/helpers/.keep +0 -0
- data/examples/five-letter-word-game/test/integration/.keep +0 -0
- data/examples/five-letter-word-game/test/mailers/.keep +0 -0
- data/examples/five-letter-word-game/test/models/.keep +0 -0
- data/examples/five-letter-word-game/test/test_helper.rb +10 -0
- data/examples/five-letter-word-game/tmp/.keep +0 -0
- data/examples/five-letter-word-game/vendor/assets/javascripts/.keep +0 -0
- data/examples/five-letter-word-game/vendor/assets/stylesheets/.keep +0 -0
- data/examples/smoke_test/.gitignore +21 -0
- data/examples/smoke_test/Gemfile +59 -0
- data/examples/smoke_test/Gemfile.lock +289 -0
- data/examples/smoke_test/README.md +24 -0
- data/examples/smoke_test/Rakefile +6 -0
- data/examples/smoke_test/app/assets/config/manifest.js +3 -0
- data/examples/smoke_test/app/assets/images/.keep +0 -0
- data/examples/smoke_test/app/assets/javascripts/application.js +15 -0
- data/examples/smoke_test/app/assets/javascripts/cable.js +13 -0
- data/examples/smoke_test/app/assets/javascripts/channels/.keep +0 -0
- data/examples/smoke_test/app/assets/stylesheets/application.css +15 -0
- data/examples/smoke_test/app/channels/application_cable/channel.rb +4 -0
- data/examples/smoke_test/app/channels/application_cable/connection.rb +4 -0
- data/examples/smoke_test/app/controllers/app_controller.rb +5 -0
- data/examples/smoke_test/app/controllers/application_controller.rb +3 -0
- data/examples/smoke_test/app/helpers/application_helper.rb +2 -0
- data/examples/smoke_test/app/hyperloop/components/hello.rb +25 -0
- data/examples/smoke_test/app/hyperloop/operations/operations/nested_send_to_all.rb +7 -0
- data/examples/smoke_test/app/hyperloop/operations/send_to_all.rb +6 -0
- data/examples/smoke_test/app/hyperloop/stores/messages.rb +4 -0
- data/examples/smoke_test/app/jobs/application_job.rb +2 -0
- data/examples/smoke_test/app/mailers/application_mailer.rb +4 -0
- data/examples/smoke_test/app/models/application_record.rb +3 -0
- data/examples/smoke_test/app/models/concerns/.keep +0 -0
- data/examples/smoke_test/app/policies/application_policy.rb +8 -0
- data/examples/smoke_test/app/views/layouts/application.html.erb +14 -0
- data/examples/smoke_test/app/views/layouts/mailer.html.erb +13 -0
- data/examples/smoke_test/app/views/layouts/mailer.text.erb +1 -0
- data/examples/smoke_test/bin/bundle +3 -0
- data/examples/smoke_test/bin/rails +9 -0
- data/examples/smoke_test/bin/rake +9 -0
- data/examples/smoke_test/bin/setup +34 -0
- data/examples/smoke_test/bin/spring +17 -0
- data/examples/smoke_test/bin/update +29 -0
- data/examples/smoke_test/config.ru +5 -0
- data/examples/smoke_test/config/application.rb +15 -0
- data/examples/smoke_test/config/boot.rb +3 -0
- data/examples/smoke_test/config/cable.yml +9 -0
- data/examples/smoke_test/config/database.yml +25 -0
- data/examples/smoke_test/config/environment.rb +5 -0
- data/examples/smoke_test/config/environments/development.rb +54 -0
- data/examples/smoke_test/config/environments/production.rb +86 -0
- data/examples/smoke_test/config/environments/test.rb +42 -0
- data/examples/smoke_test/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/smoke_test/config/initializers/assets.rb +11 -0
- data/examples/smoke_test/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/smoke_test/config/initializers/cookies_serializer.rb +5 -0
- data/examples/smoke_test/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/smoke_test/config/initializers/hyperloop.rb +32 -0
- data/examples/smoke_test/config/initializers/inflections.rb +16 -0
- data/examples/smoke_test/config/initializers/mime_types.rb +4 -0
- data/examples/smoke_test/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/smoke_test/config/initializers/session_store.rb +3 -0
- data/examples/smoke_test/config/initializers/wrap_parameters.rb +14 -0
- data/examples/smoke_test/config/locales/en.yml +23 -0
- data/examples/smoke_test/config/puma.rb +47 -0
- data/examples/smoke_test/config/routes.rb +5 -0
- data/examples/smoke_test/config/secrets.yml +22 -0
- data/examples/smoke_test/config/spring.rb +6 -0
- data/examples/smoke_test/db/seeds.rb +7 -0
- data/examples/smoke_test/lib/assets/.keep +0 -0
- data/examples/smoke_test/lib/tasks/.keep +0 -0
- data/examples/smoke_test/log/.keep +0 -0
- data/examples/smoke_test/public/404.html +67 -0
- data/examples/smoke_test/public/422.html +67 -0
- data/examples/smoke_test/public/500.html +66 -0
- data/examples/smoke_test/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/smoke_test/public/apple-touch-icon.png +0 -0
- data/examples/smoke_test/public/favicon.ico +0 -0
- data/examples/smoke_test/public/robots.txt +5 -0
- data/examples/smoke_test/test/controllers/.keep +0 -0
- data/examples/smoke_test/test/fixtures/.keep +0 -0
- data/examples/smoke_test/test/fixtures/files/.keep +0 -0
- data/examples/smoke_test/test/helpers/.keep +0 -0
- data/examples/smoke_test/test/integration/.keep +0 -0
- data/examples/smoke_test/test/mailers/.keep +0 -0
- data/examples/smoke_test/test/models/.keep +0 -0
- data/examples/smoke_test/test/test_helper.rb +10 -0
- data/examples/smoke_test/tmp/.keep +0 -0
- data/examples/smoke_test/vendor/assets/javascripts/.keep +0 -0
- data/examples/smoke_test/vendor/assets/stylesheets/.keep +0 -0
- data/hyper-operation.gemspec +44 -0
- data/lib/hyper-operation.rb +59 -0
- data/lib/hyper-operation/api.rb +154 -0
- data/lib/hyper-operation/boot.rb +24 -0
- data/lib/hyper-operation/call_by_class_name.rb +60 -0
- data/lib/hyper-operation/delay_and_interval.rb +9 -0
- data/lib/hyper-operation/engine.rb +11 -0
- data/lib/hyper-operation/exception.rb +13 -0
- data/lib/hyper-operation/filters/acting_user.rb +19 -0
- data/lib/hyper-operation/filters/outbound_filter.rb +9 -0
- data/lib/hyper-operation/filters/simple_hash.rb +22 -0
- data/lib/hyper-operation/opal_patches.rb +39 -0
- data/lib/hyper-operation/promise.rb +347 -0
- data/lib/hyper-operation/railway.rb +5 -0
- data/lib/hyper-operation/railway/dispatcher.rb +31 -0
- data/lib/hyper-operation/railway/operation_wrapper.rb +106 -0
- data/lib/hyper-operation/railway/params_wrapper.rb +124 -0
- data/lib/hyper-operation/railway/run.rb +140 -0
- data/lib/hyper-operation/railway/validations.rb +63 -0
- data/lib/hyper-operation/server_op.rb +98 -0
- data/lib/hyper-operation/transport/acting_user.rb +6 -0
- data/lib/hyper-operation/transport/action_cable.rb +39 -0
- data/lib/hyper-operation/transport/active_record.rb +15 -0
- data/lib/hyper-operation/transport/client_drivers.rb +210 -0
- data/lib/hyper-operation/transport/connection.rb +170 -0
- data/lib/hyper-operation/transport/hyperloop.rb +165 -0
- data/lib/hyper-operation/transport/hyperloop_controller.rb +184 -0
- data/lib/hyper-operation/transport/pluck.rb +6 -0
- data/lib/hyper-operation/transport/policy.rb +535 -0
- data/lib/hyper-operation/version.rb +5 -0
- data/lib/sources/hyperloop/pusher.js +98 -0
- metadata +628 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// Action Cable provides the framework to deal with WebSockets in Rails.
|
2
|
+
// You can generate new channels where WebSocket features live using the rails generate channel command.
|
3
|
+
//
|
4
|
+
//= require action_cable
|
5
|
+
//= require_self
|
6
|
+
//= require_tree ./channels
|
7
|
+
|
8
|
+
(function() {
|
9
|
+
this.App || (this.App = {});
|
10
|
+
|
11
|
+
App.cable = ActionCable.createConsumer();
|
12
|
+
|
13
|
+
}).call(this);
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
::User # force User Model to load so we can get the policies up!
|
2
|
+
# Note is important to fully qualify the name otherwise rails gets
|
3
|
+
# confused when autoloading, and you will get an error when files changed
|
4
|
+
# during development. see http://stackoverflow.com/questions/17561697/argumenterror-a-copy-of-applicationcontroller-has-been-removed-from-the-module/23008837#23008837
|
5
|
+
|
6
|
+
class ApplicationController < ActionController::Base
|
7
|
+
protect_from_forgery with: :exception
|
8
|
+
|
9
|
+
def acting_user
|
10
|
+
session.delete 'hyperloop-dummy-init' unless session.id
|
11
|
+
::User.find(session.id)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
File without changes
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'stores/store'
|
2
|
+
class App < React::Component::Base
|
3
|
+
|
4
|
+
render(DIV) do
|
5
|
+
puts "rendering: game_state = #{Store.game_state}"
|
6
|
+
puts "their_id: #{Store.state.their_id}, my_id: #{Store.my_id} words: #{Store.state.word}"
|
7
|
+
DIV { Store.message } if Store.message
|
8
|
+
send Store.game_state # for each game_state we have a method below...
|
9
|
+
Guesses() unless Store.my_guesses.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def initializing
|
13
|
+
SPAN { '...' }
|
14
|
+
end
|
15
|
+
|
16
|
+
def picking_word
|
17
|
+
InputWord label: 'pick a five letter word', button: 'play', operation: Ops::ReadyToPlay
|
18
|
+
end
|
19
|
+
|
20
|
+
def waiting_for_other_player
|
21
|
+
SPAN { "Your word is: #{Store.my_word}. Waiting for the other player to pick their word..." }
|
22
|
+
BUTTON { 'Change Your Word' }.on(:click) { Ops::ChangeWord() }
|
23
|
+
end
|
24
|
+
|
25
|
+
def waiting_for_your_guess
|
26
|
+
InputWord label: 'guess a word', button: 'guess', operation: Ops::Guess
|
27
|
+
end
|
28
|
+
|
29
|
+
def waiting_for_their_guess
|
30
|
+
SPAN { 'waiting for the other player to guess...' }
|
31
|
+
end
|
32
|
+
|
33
|
+
def waiting_for_a_clue_from_them
|
34
|
+
SPAN { 'waiting for the other player to give you the number correct...' }
|
35
|
+
end
|
36
|
+
|
37
|
+
def waiting_for_a_clue_from_you
|
38
|
+
SPAN { "Your word is '#{Store.my_word}'." }
|
39
|
+
SELECT do
|
40
|
+
OPTION(selected: true, disabled: true) { "How many correct in '#{Store.current_guess}'?" }
|
41
|
+
(0..5).each { |count| OPTION(value: count) { count.to_s } }
|
42
|
+
OPTION(value: :win) { "#{Store.current_guess} is correct!"}
|
43
|
+
end.on(:change) do |e|
|
44
|
+
if e.target.value == :win
|
45
|
+
Ops::YouWin()
|
46
|
+
else
|
47
|
+
Ops::Clue their_word: Store.current_guess, my_word: Store.my_word, correct: e.target.value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def you_win
|
53
|
+
DIV { "YOU WIN :-)" }
|
54
|
+
play_again
|
55
|
+
end
|
56
|
+
|
57
|
+
def they_win
|
58
|
+
DIV { "they won :-("}
|
59
|
+
play_again
|
60
|
+
end
|
61
|
+
|
62
|
+
def play_again
|
63
|
+
BUTTON { 'Play Again!' }.on(:click) { Ops::PlayAgain() }
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class InputWord < React::Component::Base
|
2
|
+
param :label
|
3
|
+
param :button
|
4
|
+
param :operation
|
5
|
+
render(DIV) do
|
6
|
+
LABEL { params.label }
|
7
|
+
INPUT(class: :word)
|
8
|
+
BUTTON { params.button }.on(:click) do
|
9
|
+
params.operation.run(word: Element[dom_node].find('.word').value)
|
10
|
+
.fail { |e| alert e.message }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# dummy user model... just creates an object that responds to #id and
|
2
|
+
# is equal to all other instances that have the the same id
|
3
|
+
class User
|
4
|
+
def initialize(id)
|
5
|
+
@id = id
|
6
|
+
end
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
other && id == other.id
|
10
|
+
end
|
11
|
+
|
12
|
+
def eql?(other)
|
13
|
+
self == other
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(id)
|
17
|
+
new(id) if id
|
18
|
+
end
|
19
|
+
|
20
|
+
def hash
|
21
|
+
id.hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
@id.to_s
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Ops
|
2
|
+
class Base < Hyperloop::ServerOp
|
3
|
+
# base class for all the other server side operations
|
4
|
+
# All operations take the acting_user and add outbound
|
5
|
+
# sender and other_player params which are just the ids.
|
6
|
+
|
7
|
+
param :acting_user
|
8
|
+
outbound :sender
|
9
|
+
outbound :other_player
|
10
|
+
|
11
|
+
# partners holds a hash of partner pairs i.e. x => y, y => x
|
12
|
+
# if z is waiting for a partner the hash holds z => nil
|
13
|
+
|
14
|
+
def self.partners
|
15
|
+
@partners ||= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
# find the waiting player
|
19
|
+
|
20
|
+
def waiting_player
|
21
|
+
Base.partners.key(nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
# for a given acting user find the partner
|
25
|
+
|
26
|
+
def other_player
|
27
|
+
Base.partners[params.acting_user]
|
28
|
+
end
|
29
|
+
|
30
|
+
# either attach the acting_user to the waiting player
|
31
|
+
# of if there is no waiting player, make acting_user the waiting player
|
32
|
+
|
33
|
+
def partner_up
|
34
|
+
if waiting_player
|
35
|
+
params.other_player = waiting_player.id
|
36
|
+
Base.partners[params.acting_user] = waiting_player
|
37
|
+
Base.partners[waiting_player] = params.acting_user
|
38
|
+
elsif !Base.partners.key?(params.acting_user)
|
39
|
+
Base.partners[params.acting_user] = nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# unhook partners at game end
|
44
|
+
|
45
|
+
def unpartner
|
46
|
+
Base.partners.delete other_player
|
47
|
+
Base.partners.delete params.acting_user
|
48
|
+
end
|
49
|
+
|
50
|
+
# check words for validity
|
51
|
+
|
52
|
+
def five_unique_letters
|
53
|
+
return true if params.word.split('').uniq.join =~ /^[a-zA-Z]{5}$/
|
54
|
+
abort "words and guesses must have 5 different letters"
|
55
|
+
end
|
56
|
+
|
57
|
+
# check clue for accuracy
|
58
|
+
|
59
|
+
def check_clue
|
60
|
+
params.true_count =
|
61
|
+
(Set.new(params.their_word.split('')) & params.my_word.split('')).count
|
62
|
+
end
|
63
|
+
|
64
|
+
# grab the ids from the two players
|
65
|
+
step { params.other_player = other_player && other_player.id }
|
66
|
+
step { params.sender = params.acting_user.id }
|
67
|
+
# save the value of other player in case the subclass changes it
|
68
|
+
step { @current_other_player = other_player }
|
69
|
+
|
70
|
+
# dispatch to both players. The other player may be set or removed during
|
71
|
+
# the operation, so we dispatch to the before and after values
|
72
|
+
dispatch_to { [params.acting_user, other_player, @current_other_player] }
|
73
|
+
end
|
74
|
+
|
75
|
+
class ReadyToPlay < Base
|
76
|
+
param :word, type: String
|
77
|
+
validate :five_unique_letters
|
78
|
+
end
|
79
|
+
|
80
|
+
class ChangeWord < Base
|
81
|
+
end
|
82
|
+
|
83
|
+
class Guess < Base
|
84
|
+
param :word
|
85
|
+
validate :five_unique_letters
|
86
|
+
end
|
87
|
+
|
88
|
+
class Clue < Base
|
89
|
+
param :their_word
|
90
|
+
param :my_word
|
91
|
+
param :correct, type: Integer, min: 0, max: 5
|
92
|
+
outbound :true_count
|
93
|
+
step :check_clue
|
94
|
+
end
|
95
|
+
|
96
|
+
class YouWin < Base
|
97
|
+
param message: nil
|
98
|
+
step :unpartner
|
99
|
+
end
|
100
|
+
|
101
|
+
class Join < Base
|
102
|
+
step :partner_up
|
103
|
+
end
|
104
|
+
|
105
|
+
class ShareState < Base
|
106
|
+
param :guesses
|
107
|
+
param :word
|
108
|
+
param :current_guesser, nils: true
|
109
|
+
param :current_guess, nils: true
|
110
|
+
param :message
|
111
|
+
end
|
112
|
+
|
113
|
+
class PlayAgain < Hyperloop::Operation
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'operations/ops'
|
2
|
+
class Store < Hyperloop::Store
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def my_guesses
|
6
|
+
state.guesses[my_id]
|
7
|
+
end
|
8
|
+
|
9
|
+
def my_word
|
10
|
+
state.word[my_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
state :current_guess, reader: true
|
14
|
+
|
15
|
+
def message
|
16
|
+
state.message[my_id]
|
17
|
+
end
|
18
|
+
|
19
|
+
def my_id
|
20
|
+
Hyperloop::Application.acting_user_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def game_state
|
24
|
+
if !my_word
|
25
|
+
:picking_word
|
26
|
+
elsif !state.word[state.their_id]
|
27
|
+
:waiting_for_other_player
|
28
|
+
elsif state.winner
|
29
|
+
:"#{state.winner == my_id ? 'you' : 'they'}_win"
|
30
|
+
elsif state.current_guess
|
31
|
+
:"waiting_for_a_clue_from_#{state.current_guesser == my_id ? 'them' : 'you'}"
|
32
|
+
else
|
33
|
+
:"waiting_for_#{state.current_guesser == my_id ? 'your' : 'their'}_guess"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def game_over?
|
38
|
+
game_state =~ /_win$/
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
mutate.guesses Hash.new { |guesses, player| guesses[player] = [] }
|
43
|
+
mutate.winner nil
|
44
|
+
mutate.word Hash.new
|
45
|
+
mutate.current_guesser nil
|
46
|
+
mutate.current_guess nil
|
47
|
+
mutate.their_id nil
|
48
|
+
mutate.message Hash.new
|
49
|
+
Ops::Join.run if Hyperloop.on_client?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
receives Ops::Join do |params|
|
54
|
+
puts "receiving Ops::Join(#{params})"
|
55
|
+
if state.their_id && params.sender != my_id
|
56
|
+
Ops::ShareState(
|
57
|
+
guesses: state.guesses,
|
58
|
+
word: state.word,
|
59
|
+
current_guesser: state.current_guesser,
|
60
|
+
current_guess: state.current_guess,
|
61
|
+
message: state.message
|
62
|
+
)
|
63
|
+
else
|
64
|
+
mutate.their_id params.sender != my_id ? params.sender : params.other_player
|
65
|
+
Ops::ReadyToPlay.run(word: state.word[my_id]) if state.word[my_id]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
receives Ops::ShareState do |params|
|
70
|
+
puts "receiving Ops::ShareState(#{params})"
|
71
|
+
if params.sender != my_id
|
72
|
+
params.guesses.each { |player, guesses| mutate.guesses[player] = guesses }
|
73
|
+
mutate.word params.word
|
74
|
+
mutate.current_guesser params.current_guesser
|
75
|
+
mutate.current_guess params.current_guess
|
76
|
+
mutate.message params.message
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
receives Ops::ReadyToPlay do |params|
|
81
|
+
puts "receiving Ops::ReadyToPlay(#{params})"
|
82
|
+
mutate.current_guesser params.sender unless state.current_guesser
|
83
|
+
mutate.word[params.sender] = params.word
|
84
|
+
end
|
85
|
+
|
86
|
+
receives Ops::ChangeWord do |params|
|
87
|
+
puts "receiving Ops::ChangeWord(#{params})"
|
88
|
+
mutate.word[params.sender] = nil
|
89
|
+
mutate.current_guesser nil if params.sender == state.current_guesser
|
90
|
+
end
|
91
|
+
|
92
|
+
receives Ops::Guess do |params|
|
93
|
+
puts "receiving Ops::Guess(#{params})"
|
94
|
+
mutate.current_guess params.word
|
95
|
+
mutate.message({})
|
96
|
+
end
|
97
|
+
|
98
|
+
receives Ops::Clue do |params|
|
99
|
+
puts "receiving Ops::Clue(#{params})"
|
100
|
+
mutate.guesses[params.other_player] << [state.current_guess, params.true_count]
|
101
|
+
if params.true_count == params.correct
|
102
|
+
mutate.current_guesser params.sender
|
103
|
+
else
|
104
|
+
mutate.message[params.sender] =
|
105
|
+
"That was a bogus clue. There are #{params.true_count} correct in #{current_guess}. They get a free guess!"
|
106
|
+
mutate.message[params.other_player] =
|
107
|
+
"They tried to give you a bogus clue! There are #{params.true_count} correct in #{current_guess}. Have a free turn!"
|
108
|
+
end
|
109
|
+
mutate.current_guess nil
|
110
|
+
end
|
111
|
+
|
112
|
+
receives Ops::YouWin do |params|
|
113
|
+
puts "receiving Ops::YouWin(#{params})"
|
114
|
+
mutate.winner params.other_player
|
115
|
+
mutate.message params.message
|
116
|
+
end
|
117
|
+
|
118
|
+
receives Ops::PlayAgain, :setup
|
119
|
+
receives Hyperloop::Application::Boot, :setup
|
120
|
+
end
|