hyper-operation 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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