hyper-operation 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +49 -0
  3. data/CODE_OF_CONDUCT.md +49 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +324 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +708 -0
  8. data/Rakefile +4 -0
  9. data/examples/chat-app/.gitignore +21 -0
  10. data/examples/chat-app/Gemfile +57 -0
  11. data/examples/chat-app/Gemfile.lock +282 -0
  12. data/examples/chat-app/README.md +3 -0
  13. data/examples/chat-app/Rakefile +6 -0
  14. data/examples/chat-app/app/assets/config/manifest.js +3 -0
  15. data/examples/chat-app/app/assets/images/.keep +0 -0
  16. data/examples/chat-app/app/assets/javascripts/application.js +3 -0
  17. data/examples/chat-app/app/assets/javascripts/cable.js +13 -0
  18. data/examples/chat-app/app/assets/javascripts/channels/.keep +0 -0
  19. data/examples/chat-app/app/assets/stylesheets/application.css +15 -0
  20. data/examples/chat-app/app/channels/application_cable/channel.rb +4 -0
  21. data/examples/chat-app/app/channels/application_cable/connection.rb +4 -0
  22. data/examples/chat-app/app/controllers/application_controller.rb +3 -0
  23. data/examples/chat-app/app/controllers/concerns/.keep +0 -0
  24. data/examples/chat-app/app/controllers/home_controller.rb +5 -0
  25. data/examples/chat-app/app/helpers/application_helper.rb +2 -0
  26. data/examples/chat-app/app/hyperloop/components/app.rb +11 -0
  27. data/examples/chat-app/app/hyperloop/components/formatted_div.rb +13 -0
  28. data/examples/chat-app/app/hyperloop/components/input_box.rb +29 -0
  29. data/examples/chat-app/app/hyperloop/components/message.rb +29 -0
  30. data/examples/chat-app/app/hyperloop/components/messages.rb +9 -0
  31. data/examples/chat-app/app/hyperloop/components/nav.rb +30 -0
  32. data/examples/chat-app/app/hyperloop/operations/operations.rb +56 -0
  33. data/examples/chat-app/app/hyperloop/stores/message_store.rb +23 -0
  34. data/examples/chat-app/app/models/application_record.rb +3 -0
  35. data/examples/chat-app/app/models/concerns/.keep +0 -0
  36. data/examples/chat-app/app/models/models.rb +2 -0
  37. data/examples/chat-app/app/models/public/.keep +0 -0
  38. data/examples/chat-app/app/models/public/announcement.rb +8 -0
  39. data/examples/chat-app/app/policies/application_policy.rb +5 -0
  40. data/examples/chat-app/app/views/layouts/application.html.erb +51 -0
  41. data/examples/chat-app/bin/bundle +3 -0
  42. data/examples/chat-app/bin/rails +9 -0
  43. data/examples/chat-app/bin/rake +9 -0
  44. data/examples/chat-app/bin/setup +34 -0
  45. data/examples/chat-app/bin/spring +17 -0
  46. data/examples/chat-app/bin/update +29 -0
  47. data/examples/chat-app/config.ru +5 -0
  48. data/examples/chat-app/config/application.rb +13 -0
  49. data/examples/chat-app/config/boot.rb +3 -0
  50. data/examples/chat-app/config/cable.yml +9 -0
  51. data/examples/chat-app/config/database.yml +25 -0
  52. data/examples/chat-app/config/environment.rb +5 -0
  53. data/examples/chat-app/config/environments/development.rb +56 -0
  54. data/examples/chat-app/config/environments/production.rb +86 -0
  55. data/examples/chat-app/config/environments/test.rb +42 -0
  56. data/examples/chat-app/config/initializers/application_controller_renderer.rb +6 -0
  57. data/examples/chat-app/config/initializers/assets.rb +11 -0
  58. data/examples/chat-app/config/initializers/backtrace_silencers.rb +7 -0
  59. data/examples/chat-app/config/initializers/cookies_serializer.rb +5 -0
  60. data/examples/chat-app/config/initializers/filter_parameter_logging.rb +4 -0
  61. data/examples/chat-app/config/initializers/hyperloop.rb +4 -0
  62. data/examples/chat-app/config/initializers/inflections.rb +16 -0
  63. data/examples/chat-app/config/initializers/mime_types.rb +4 -0
  64. data/examples/chat-app/config/initializers/new_framework_defaults.rb +24 -0
  65. data/examples/chat-app/config/initializers/session_store.rb +3 -0
  66. data/examples/chat-app/config/initializers/wrap_parameters.rb +14 -0
  67. data/examples/chat-app/config/locales/en.yml +23 -0
  68. data/examples/chat-app/config/puma.rb +47 -0
  69. data/examples/chat-app/config/routes.rb +5 -0
  70. data/examples/chat-app/config/secrets.yml +22 -0
  71. data/examples/chat-app/config/spring.rb +6 -0
  72. data/examples/chat-app/db/seeds.rb +7 -0
  73. data/examples/chat-app/lib/assets/.keep +0 -0
  74. data/examples/chat-app/lib/tasks/.keep +0 -0
  75. data/examples/chat-app/log/.keep +0 -0
  76. data/examples/chat-app/public/404.html +67 -0
  77. data/examples/chat-app/public/422.html +67 -0
  78. data/examples/chat-app/public/500.html +66 -0
  79. data/examples/chat-app/public/apple-touch-icon-precomposed.png +0 -0
  80. data/examples/chat-app/public/apple-touch-icon.png +0 -0
  81. data/examples/chat-app/public/favicon.ico +0 -0
  82. data/examples/chat-app/public/robots.txt +5 -0
  83. data/examples/chat-app/test/controllers/.keep +0 -0
  84. data/examples/chat-app/test/fixtures/.keep +0 -0
  85. data/examples/chat-app/test/fixtures/files/.keep +0 -0
  86. data/examples/chat-app/test/helpers/.keep +0 -0
  87. data/examples/chat-app/test/integration/.keep +0 -0
  88. data/examples/chat-app/test/mailers/.keep +0 -0
  89. data/examples/chat-app/test/models/.keep +0 -0
  90. data/examples/chat-app/test/test_helper.rb +10 -0
  91. data/examples/chat-app/tmp/.keep +0 -0
  92. data/examples/chat-app/vendor/assets/javascripts/.keep +0 -0
  93. data/examples/chat-app/vendor/assets/stylesheets/.keep +0 -0
  94. data/examples/five-letter-word-game/.gitignore +21 -0
  95. data/examples/five-letter-word-game/Gemfile +57 -0
  96. data/examples/five-letter-word-game/Gemfile.lock +282 -0
  97. data/examples/five-letter-word-game/README.md +24 -0
  98. data/examples/five-letter-word-game/Rakefile +6 -0
  99. data/examples/five-letter-word-game/app/assets/config/manifest.js +3 -0
  100. data/examples/five-letter-word-game/app/assets/images/.keep +0 -0
  101. data/examples/five-letter-word-game/app/assets/javascripts/application.js +3 -0
  102. data/examples/five-letter-word-game/app/assets/javascripts/cable.js +13 -0
  103. data/examples/five-letter-word-game/app/assets/javascripts/channels/.keep +0 -0
  104. data/examples/five-letter-word-game/app/assets/stylesheets/application.css +15 -0
  105. data/examples/five-letter-word-game/app/channels/application_cable/channel.rb +4 -0
  106. data/examples/five-letter-word-game/app/channels/application_cable/connection.rb +4 -0
  107. data/examples/five-letter-word-game/app/controllers/application_controller.rb +14 -0
  108. data/examples/five-letter-word-game/app/controllers/concerns/.keep +0 -0
  109. data/examples/five-letter-word-game/app/controllers/home_controller.rb +5 -0
  110. data/examples/five-letter-word-game/app/helpers/application_helper.rb +2 -0
  111. data/examples/five-letter-word-game/app/hyperloop/components/app.rb +65 -0
  112. data/examples/five-letter-word-game/app/hyperloop/components/guesses.rb +8 -0
  113. data/examples/five-letter-word-game/app/hyperloop/components/input_word.rb +13 -0
  114. data/examples/five-letter-word-game/app/hyperloop/models/user.rb +27 -0
  115. data/examples/five-letter-word-game/app/hyperloop/operations/ops.rb +115 -0
  116. data/examples/five-letter-word-game/app/hyperloop/stores/store.rb +120 -0
  117. data/examples/five-letter-word-game/app/jobs/application_job.rb +2 -0
  118. data/examples/five-letter-word-game/app/mailers/application_mailer.rb +4 -0
  119. data/examples/five-letter-word-game/app/models/application_record.rb +3 -0
  120. data/examples/five-letter-word-game/app/models/concerns/.keep +0 -0
  121. data/examples/five-letter-word-game/app/policies/user_policy.rb +4 -0
  122. data/examples/five-letter-word-game/app/views/layouts/application.html.erb +14 -0
  123. data/examples/five-letter-word-game/app/views/layouts/mailer.html.erb +13 -0
  124. data/examples/five-letter-word-game/app/views/layouts/mailer.text.erb +1 -0
  125. data/examples/five-letter-word-game/bin/bundle +3 -0
  126. data/examples/five-letter-word-game/bin/rails +9 -0
  127. data/examples/five-letter-word-game/bin/rake +9 -0
  128. data/examples/five-letter-word-game/bin/setup +34 -0
  129. data/examples/five-letter-word-game/bin/spring +17 -0
  130. data/examples/five-letter-word-game/bin/update +29 -0
  131. data/examples/five-letter-word-game/config.ru +5 -0
  132. data/examples/five-letter-word-game/config/application.rb +12 -0
  133. data/examples/five-letter-word-game/config/boot.rb +3 -0
  134. data/examples/five-letter-word-game/config/cable.yml +9 -0
  135. data/examples/five-letter-word-game/config/database.yml +25 -0
  136. data/examples/five-letter-word-game/config/environment.rb +5 -0
  137. data/examples/five-letter-word-game/config/environments/development.rb +56 -0
  138. data/examples/five-letter-word-game/config/environments/production.rb +86 -0
  139. data/examples/five-letter-word-game/config/environments/test.rb +42 -0
  140. data/examples/five-letter-word-game/config/initializers/application_controller_renderer.rb +6 -0
  141. data/examples/five-letter-word-game/config/initializers/assets.rb +11 -0
  142. data/examples/five-letter-word-game/config/initializers/backtrace_silencers.rb +7 -0
  143. data/examples/five-letter-word-game/config/initializers/cookies_serializer.rb +5 -0
  144. data/examples/five-letter-word-game/config/initializers/filter_parameter_logging.rb +4 -0
  145. data/examples/five-letter-word-game/config/initializers/hyperloop.rb +3 -0
  146. data/examples/five-letter-word-game/config/initializers/inflections.rb +16 -0
  147. data/examples/five-letter-word-game/config/initializers/mime_types.rb +4 -0
  148. data/examples/five-letter-word-game/config/initializers/new_framework_defaults.rb +24 -0
  149. data/examples/five-letter-word-game/config/initializers/session_store.rb +3 -0
  150. data/examples/five-letter-word-game/config/initializers/wrap_parameters.rb +14 -0
  151. data/examples/five-letter-word-game/config/locales/en.yml +23 -0
  152. data/examples/five-letter-word-game/config/puma.rb +47 -0
  153. data/examples/five-letter-word-game/config/routes.rb +5 -0
  154. data/examples/five-letter-word-game/config/secrets.yml +22 -0
  155. data/examples/five-letter-word-game/config/spring.rb +6 -0
  156. data/examples/five-letter-word-game/db/schema.rb +28 -0
  157. data/examples/five-letter-word-game/db/seeds.rb +7 -0
  158. data/examples/five-letter-word-game/lib/assets/.keep +0 -0
  159. data/examples/five-letter-word-game/lib/tasks/.keep +0 -0
  160. data/examples/five-letter-word-game/log/.keep +0 -0
  161. data/examples/five-letter-word-game/public/404.html +67 -0
  162. data/examples/five-letter-word-game/public/422.html +67 -0
  163. data/examples/five-letter-word-game/public/500.html +66 -0
  164. data/examples/five-letter-word-game/public/apple-touch-icon-precomposed.png +0 -0
  165. data/examples/five-letter-word-game/public/apple-touch-icon.png +0 -0
  166. data/examples/five-letter-word-game/public/favicon.ico +0 -0
  167. data/examples/five-letter-word-game/public/robots.txt +5 -0
  168. data/examples/five-letter-word-game/test/controllers/.keep +0 -0
  169. data/examples/five-letter-word-game/test/fixtures/.keep +0 -0
  170. data/examples/five-letter-word-game/test/fixtures/files/.keep +0 -0
  171. data/examples/five-letter-word-game/test/helpers/.keep +0 -0
  172. data/examples/five-letter-word-game/test/integration/.keep +0 -0
  173. data/examples/five-letter-word-game/test/mailers/.keep +0 -0
  174. data/examples/five-letter-word-game/test/models/.keep +0 -0
  175. data/examples/five-letter-word-game/test/test_helper.rb +10 -0
  176. data/examples/five-letter-word-game/tmp/.keep +0 -0
  177. data/examples/five-letter-word-game/vendor/assets/javascripts/.keep +0 -0
  178. data/examples/five-letter-word-game/vendor/assets/stylesheets/.keep +0 -0
  179. data/examples/smoke_test/.gitignore +21 -0
  180. data/examples/smoke_test/Gemfile +59 -0
  181. data/examples/smoke_test/Gemfile.lock +289 -0
  182. data/examples/smoke_test/README.md +24 -0
  183. data/examples/smoke_test/Rakefile +6 -0
  184. data/examples/smoke_test/app/assets/config/manifest.js +3 -0
  185. data/examples/smoke_test/app/assets/images/.keep +0 -0
  186. data/examples/smoke_test/app/assets/javascripts/application.js +15 -0
  187. data/examples/smoke_test/app/assets/javascripts/cable.js +13 -0
  188. data/examples/smoke_test/app/assets/javascripts/channels/.keep +0 -0
  189. data/examples/smoke_test/app/assets/stylesheets/application.css +15 -0
  190. data/examples/smoke_test/app/channels/application_cable/channel.rb +4 -0
  191. data/examples/smoke_test/app/channels/application_cable/connection.rb +4 -0
  192. data/examples/smoke_test/app/controllers/app_controller.rb +5 -0
  193. data/examples/smoke_test/app/controllers/application_controller.rb +3 -0
  194. data/examples/smoke_test/app/helpers/application_helper.rb +2 -0
  195. data/examples/smoke_test/app/hyperloop/components/hello.rb +25 -0
  196. data/examples/smoke_test/app/hyperloop/operations/operations/nested_send_to_all.rb +7 -0
  197. data/examples/smoke_test/app/hyperloop/operations/send_to_all.rb +6 -0
  198. data/examples/smoke_test/app/hyperloop/stores/messages.rb +4 -0
  199. data/examples/smoke_test/app/jobs/application_job.rb +2 -0
  200. data/examples/smoke_test/app/mailers/application_mailer.rb +4 -0
  201. data/examples/smoke_test/app/models/application_record.rb +3 -0
  202. data/examples/smoke_test/app/models/concerns/.keep +0 -0
  203. data/examples/smoke_test/app/policies/application_policy.rb +8 -0
  204. data/examples/smoke_test/app/views/layouts/application.html.erb +14 -0
  205. data/examples/smoke_test/app/views/layouts/mailer.html.erb +13 -0
  206. data/examples/smoke_test/app/views/layouts/mailer.text.erb +1 -0
  207. data/examples/smoke_test/bin/bundle +3 -0
  208. data/examples/smoke_test/bin/rails +9 -0
  209. data/examples/smoke_test/bin/rake +9 -0
  210. data/examples/smoke_test/bin/setup +34 -0
  211. data/examples/smoke_test/bin/spring +17 -0
  212. data/examples/smoke_test/bin/update +29 -0
  213. data/examples/smoke_test/config.ru +5 -0
  214. data/examples/smoke_test/config/application.rb +15 -0
  215. data/examples/smoke_test/config/boot.rb +3 -0
  216. data/examples/smoke_test/config/cable.yml +9 -0
  217. data/examples/smoke_test/config/database.yml +25 -0
  218. data/examples/smoke_test/config/environment.rb +5 -0
  219. data/examples/smoke_test/config/environments/development.rb +54 -0
  220. data/examples/smoke_test/config/environments/production.rb +86 -0
  221. data/examples/smoke_test/config/environments/test.rb +42 -0
  222. data/examples/smoke_test/config/initializers/application_controller_renderer.rb +6 -0
  223. data/examples/smoke_test/config/initializers/assets.rb +11 -0
  224. data/examples/smoke_test/config/initializers/backtrace_silencers.rb +7 -0
  225. data/examples/smoke_test/config/initializers/cookies_serializer.rb +5 -0
  226. data/examples/smoke_test/config/initializers/filter_parameter_logging.rb +4 -0
  227. data/examples/smoke_test/config/initializers/hyperloop.rb +32 -0
  228. data/examples/smoke_test/config/initializers/inflections.rb +16 -0
  229. data/examples/smoke_test/config/initializers/mime_types.rb +4 -0
  230. data/examples/smoke_test/config/initializers/new_framework_defaults.rb +24 -0
  231. data/examples/smoke_test/config/initializers/session_store.rb +3 -0
  232. data/examples/smoke_test/config/initializers/wrap_parameters.rb +14 -0
  233. data/examples/smoke_test/config/locales/en.yml +23 -0
  234. data/examples/smoke_test/config/puma.rb +47 -0
  235. data/examples/smoke_test/config/routes.rb +5 -0
  236. data/examples/smoke_test/config/secrets.yml +22 -0
  237. data/examples/smoke_test/config/spring.rb +6 -0
  238. data/examples/smoke_test/db/seeds.rb +7 -0
  239. data/examples/smoke_test/lib/assets/.keep +0 -0
  240. data/examples/smoke_test/lib/tasks/.keep +0 -0
  241. data/examples/smoke_test/log/.keep +0 -0
  242. data/examples/smoke_test/public/404.html +67 -0
  243. data/examples/smoke_test/public/422.html +67 -0
  244. data/examples/smoke_test/public/500.html +66 -0
  245. data/examples/smoke_test/public/apple-touch-icon-precomposed.png +0 -0
  246. data/examples/smoke_test/public/apple-touch-icon.png +0 -0
  247. data/examples/smoke_test/public/favicon.ico +0 -0
  248. data/examples/smoke_test/public/robots.txt +5 -0
  249. data/examples/smoke_test/test/controllers/.keep +0 -0
  250. data/examples/smoke_test/test/fixtures/.keep +0 -0
  251. data/examples/smoke_test/test/fixtures/files/.keep +0 -0
  252. data/examples/smoke_test/test/helpers/.keep +0 -0
  253. data/examples/smoke_test/test/integration/.keep +0 -0
  254. data/examples/smoke_test/test/mailers/.keep +0 -0
  255. data/examples/smoke_test/test/models/.keep +0 -0
  256. data/examples/smoke_test/test/test_helper.rb +10 -0
  257. data/examples/smoke_test/tmp/.keep +0 -0
  258. data/examples/smoke_test/vendor/assets/javascripts/.keep +0 -0
  259. data/examples/smoke_test/vendor/assets/stylesheets/.keep +0 -0
  260. data/hyper-operation.gemspec +44 -0
  261. data/lib/hyper-operation.rb +59 -0
  262. data/lib/hyper-operation/api.rb +154 -0
  263. data/lib/hyper-operation/boot.rb +24 -0
  264. data/lib/hyper-operation/call_by_class_name.rb +60 -0
  265. data/lib/hyper-operation/delay_and_interval.rb +9 -0
  266. data/lib/hyper-operation/engine.rb +11 -0
  267. data/lib/hyper-operation/exception.rb +13 -0
  268. data/lib/hyper-operation/filters/acting_user.rb +19 -0
  269. data/lib/hyper-operation/filters/outbound_filter.rb +9 -0
  270. data/lib/hyper-operation/filters/simple_hash.rb +22 -0
  271. data/lib/hyper-operation/opal_patches.rb +39 -0
  272. data/lib/hyper-operation/promise.rb +347 -0
  273. data/lib/hyper-operation/railway.rb +5 -0
  274. data/lib/hyper-operation/railway/dispatcher.rb +31 -0
  275. data/lib/hyper-operation/railway/operation_wrapper.rb +106 -0
  276. data/lib/hyper-operation/railway/params_wrapper.rb +124 -0
  277. data/lib/hyper-operation/railway/run.rb +140 -0
  278. data/lib/hyper-operation/railway/validations.rb +63 -0
  279. data/lib/hyper-operation/server_op.rb +98 -0
  280. data/lib/hyper-operation/transport/acting_user.rb +6 -0
  281. data/lib/hyper-operation/transport/action_cable.rb +39 -0
  282. data/lib/hyper-operation/transport/active_record.rb +15 -0
  283. data/lib/hyper-operation/transport/client_drivers.rb +210 -0
  284. data/lib/hyper-operation/transport/connection.rb +170 -0
  285. data/lib/hyper-operation/transport/hyperloop.rb +165 -0
  286. data/lib/hyper-operation/transport/hyperloop_controller.rb +184 -0
  287. data/lib/hyper-operation/transport/pluck.rb +6 -0
  288. data/lib/hyper-operation/transport/policy.rb +535 -0
  289. data/lib/hyper-operation/version.rb +5 -0
  290. data/lib/sources/hyperloop/pusher.js +98 -0
  291. 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
+ * ...
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,3 @@
1
+ //= require jquery
2
+ //= require jquery_ujs
3
+ //= require hyperloop-loader
@@ -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);
@@ -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,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ class HomeController < ApplicationController
2
+ def app
3
+ render_component "::App"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -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,8 @@
1
+ class Guesses < React::Component::Base
2
+ render(DIV) do
3
+ OL do
4
+ Store.my_guesses.each { |guess, no_correct| LI { "#{no_correct} in '#{guess}'" } }
5
+ end
6
+ BUTTON { 'quit' }.on(:click) { Ops::YouWin message: 'I quit' } unless Store.game_over?
7
+ end
8
+ 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