hyper-operation 0.5.11 → 0.5.12

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,110 +1,76 @@
1
- # Hyper-Operation
1
+ <div class="githubhyperloopheader">
2
2
 
3
- ## Hyper-Operation gem
3
+ <p align="center">
4
4
 
5
- Operations encapsulate business logic. In a traditional MVC architecture, Operations end up either in Controllers, Models or some other secondary construct such as service objects, helpers, or concerns. Here they are first class objects. Their job is to mutate state in the Stores and Models.
5
+ <a href="http://ruby-hyperloop.io/" alt="Hyperloop" title="Hyperloop">
6
+ <img width="350px" src="http://ruby-hyperloop.io/images/hyperloop-github-logo.png">
7
+ </a>
6
8
 
7
- + Hyperloop::Operation is the base class for Operations.
8
- + An Operation orchestrates the updating of the state of your system.
9
- + Operations also wrap asynchronous operations such as HTTP API requests.
10
- + Operations serve the role of both Action Creators and Dispatchers described in the Flux architecture.
11
- + Operations also serve as the bridge between client and server. An operation can run on the client or the server, and can be invoked remotely.
9
+ </p>
12
10
 
13
- ## Documentation and Help
11
+ <h2 align="center">The Complete Isomorphic Ruby Framework</h2>
14
12
 
15
- + Please see the [ruby-hyperloop.io](http://ruby-hyperloop.io/) website for documentation.
16
- + Join the Hyperloop [gitter.io](https://gitter.im/ruby-hyperloop/chat) chat for help and support.
13
+ <br>
17
14
 
18
- ## Installation and Setup
15
+ <a href="http://ruby-hyperloop.io/" alt="Hyperloop" title="Hyperloop">
16
+ <img src="http://ruby-hyperloop.io/images/githubhyperloopbadge.png">
17
+ </a>
19
18
 
20
- **Note: Operations require Rails currently.**
19
+ <a href="https://gitter.im/ruby-hyperloop/chat" alt="Gitter chat" title="Gitter chat">
20
+ <img src="http://ruby-hyperloop.io/images/githubgitterbadge.png">
21
+ </a>
21
22
 
22
- ### Easy Installation
23
+ [![Gem Version](https://badge.fury.io/rb/hyper-operation.svg)](https://badge.fury.io/rb/hyper-operation)
23
24
 
24
- The easiest way to install is to use the `hyper-rails` generator.
25
+ <p align="center">
26
+ <img src="http://ruby-hyperloop.io/images/HyperOperations.png" width="100" alt="Hyper-operation">
27
+ </p>
25
28
 
26
- 1. Add `gem 'hyper-rails'` to your Rails `Gemfile` development section.
27
- 2. Install the Gem: `bundle install`
28
- 3. Run the generator: `bundle exec rails g hyperloop:install --all`
29
- 4. Update the bundle: `bundle update`
29
+ </div>
30
30
 
31
- ### Manual Installation
31
+ ## Hyper-Operation GEM is part of Hyperloop GEMS family
32
32
 
33
- Add `gem 'hyper-operation'` to your Gemfile
34
- Add `//= require hyperloop-loader` to your application.rb
33
+ Build interactive Web applications quickly. Hyperloop encourages rapid development with clean, pragmatic design. With developer productivity as our highest goal, Hyperloop takes care of much of the hassle of Web development, so you can focus on innovation and delivering end-user value.
35
34
 
36
- If you want operations to interact between server and client you will have to pick a transport:
37
- ```ruby
38
- # initializers/hyperloop.rb
39
- Hyperloop.configuration do |config|
40
-
41
- # to use Action Cable
42
- config.transport = :action_cable # for rails 5+
43
-
44
- # to use Pusher (see www.pusher.com)
45
- config.transport = :pusher
46
- config.opts = {
47
- app_id: "pusher application id",
48
- key: "pusher public key",
49
- secret: "pusher secret key"
50
- }
51
-
52
- # to use Pusher Fake (creates a fake pusher service)
53
- # Its a bit weird: You have to define require pusher and
54
- # define some FAKE pusher keys first, then bring in pusher-fake
55
- # the actual key values don't matter just the order!!!
56
- require 'pusher'
57
- require 'pusher-fake'
58
- Pusher.app_id = "MY_TEST_ID" # don't bother changing these strings
59
- Pusher.key = "MY_TEST_KEY"
60
- Pusher.secret = "MY_TEST_SECRET"
61
- require 'pusher-fake/support/base'
62
- # then setup your config like pusher but merge in the pusher fake
63
- # options
64
- config.transport = :pusher
65
- config.opts = {
66
- app_id: Pusher.app_id,
67
- key: Pusher.key,
68
- secret: Pusher.secret
69
- }.merge(PusherFake.configuration.web_options)
70
-
71
- # For down and dirty simplicity use polling:
72
- config.transport = :simple_poller
73
- # change this to slow down polling, default is much faster
74
- # and hard to debug
75
- config.opts = { seconds_between_poll: 2 }
76
- end
77
- ```
35
+ One language. One model. One set of tests. The same business logic and domain models running on the clients and the server. Hyperloop is fully integrated with Rails and also gives you unfettered access to the complete universe of JavaScript libraries (including React) from within your Ruby code. Hyperloop lets you build beautiful interactive user interfaces in Ruby.
78
36
 
79
- You will also have to add at least one channel policy to authorize the connection between clients and the server.
37
+ Everything has a place in our architecture. Components deliver interactive user experiences, Operations encapsulate business logic, Models magically synchronize data between clients and servers, Policies govern authorization and Stores hold local state.
80
38
 
81
- ```ruby
82
- # app/policies/application_policy.rb
83
- class Hyperloop::ApplicationPolicy
84
- # allow any client too attach to the Hyperloop::Application for example
85
- always_allow_connection
86
- end
87
- ```
39
+ **Hyper-Operation** brings Operations which encapsulate business logic. In a traditional MVC architecture, Operations end up either in Controllers, Models or some other secondary construct such as service objects, helpers, or concerns. Here they are first class objects. Their job is to mutate state in the Stores and Models.
88
40
 
89
- See the [Channels](#channels) section for more details on authorization.
41
+ ## Getting Started
90
42
 
91
- ### Add the engine
43
+ 1. Update your Gemfile:
92
44
 
93
45
  ```ruby
94
- # config/routes.rb
95
- mount Hyperloop::Engine => '/hyperloop'
46
+ #Gemfile
47
+
48
+ gem 'hyperloop'
96
49
  ```
97
50
 
98
- ### Operation Folder Structure
51
+ 2. At the command prompt, update your bundle :
52
+
53
+ $ bundle update
54
+
55
+ 3. Run the hyperloop install generator:
56
+
57
+ $ rails g hyperloop:install
99
58
 
100
- Your Isomorphic Operations live in a `app/hyperloop/operations` folder and your server only Operations in `app/operations`
59
+ 4. Follow the guidelines to start developing your application. You may find
60
+ the following resources handy:
61
+ * [Getting Started with Hyperloop](http://ruby-hyperloop.io/start/components/)
62
+ * [Hyperloop Guides](http://ruby-hyperloop.io/docs/architecture)
63
+ * [Hyperloop Tutorial](http://ruby-hyperloop.io/tutorials)
101
64
 
102
- You will also find an `app/policies` folder with a simple access policy suited for development. Policies are how you will provide detailed access control to your Isomorphic models.
65
+ ## Community
103
66
 
104
- ## Contributing
67
+ #### Getting Help
68
+ Please **do not post** usage questions to GitHub Issues. For these types of questions use our [Gitter chatroom](https://gitter.im/ruby-hyperloop/chat) or [StackOverflow](http://stackoverflow.com/questions/tagged/hyperloop).
105
69
 
106
- Bug reports and pull requests are welcome on GitHub at https://github.com/ruby-hyperloop/hyper-operation. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Code of Conduct](https://github.com/ruby-hyperloop/hyper-operation/blob/master/CODE_OF_CONDUCT.md) code of conduct.
70
+ #### Submitting Bugs and Enhancements
71
+ [GitHub Issues](https://github.com/ruby-hyperloop/hyperloop/issues) is for suggesting enhancements and reporting bugs. Before submiting a bug make sure you do the following:
72
+ * Check out our [contributing guide](https://github.com/ruby-hyperloop/hyperloop/blob/master/CONTRIBUTING.md) for info on our release cycle.
107
73
 
108
74
  ## License
109
75
 
110
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
76
+ Hyperloop is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -23,8 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency 'hyperloop-config', '>= 0.9.7'
24
24
  spec.add_dependency 'opal-activesupport'
25
25
  spec.add_dependency 'activerecord', '>= 0.3.0'
26
- spec.add_dependency 'pusher'
27
- spec.add_dependency 'pusher-fake'
28
26
 
29
27
  spec.add_development_dependency "bundler", "~> 1.8"
30
28
  spec.add_development_dependency "rake", "~> 10.0"
@@ -35,10 +33,14 @@ Gem::Specification.new do |spec|
35
33
  spec.add_development_dependency 'hyper-react'
36
34
  spec.add_development_dependency 'opal-browser'
37
35
  spec.add_development_dependency 'sqlite3', '1.3.10'
36
+ spec.add_development_dependency 'mysql2'
38
37
  spec.add_development_dependency 'database_cleaner'
39
38
  spec.add_development_dependency 'pry'
40
39
  spec.add_development_dependency 'rspec-wait'
41
40
  spec.add_development_dependency 'puma'
42
41
  spec.add_development_dependency 'rspec-steps'
42
+ spec.add_development_dependency 'pusher'
43
+ spec.add_development_dependency 'pusher-fake'
44
+ spec.add_development_dependency 'timecop', '~>0.8.1'
43
45
 
44
46
  end
@@ -63,6 +63,11 @@ module Hyperloop
63
63
  _Railway.add_param(*args, &block)
64
64
  end
65
65
 
66
+ def inbound(*args, &block)
67
+ name, opts = ParamsWrapper.get_name_and_opts(*args)
68
+ _Railway.add_param(name, opts.merge(inbound: :true), &block)
69
+ end
70
+
66
71
  def outbound(*keys)
67
72
  keys.each { |key| _Railway.add_param(key => nil, :type => :outbound) }
68
73
  #singleton_class.outbound(*keys)
@@ -102,6 +107,11 @@ module Hyperloop
102
107
  _Railway.add_param(*args, &block)
103
108
  end
104
109
 
110
+ child.singleton_class.define_singleton_method(:inbound) do |*args, &block|
111
+ name, opts = ParamsWrapper.get_name_and_opts(*args)
112
+ _Railway.add_param(name, opts.merge(inbound: :true), &block)
113
+ end
114
+
105
115
  child.singleton_class.define_singleton_method(:outbound) do |*keys|
106
116
  keys.each { |key| _Railway.add_param(key => nil, :type => :outbound) }
107
117
  end
@@ -12,7 +12,12 @@ module Hyperloop
12
12
  end
13
13
 
14
14
  def to_h
15
- @inputs.with_indifferent_access
15
+ inputs = @inputs
16
+ if @locked
17
+ inputs = inputs.dup
18
+ self.class.inbound_params.each { |name| inputs.delete :"#{name}" }
19
+ end
20
+ inputs.with_indifferent_access
16
21
  end
17
22
 
18
23
  def to_s
@@ -39,6 +44,7 @@ module Hyperloop
39
44
 
40
45
  def add_param(*args, &block)
41
46
  type_method, name, opts, block = translate_args(*args, &block)
47
+ inbound_params << :"#{name}" if opts.delete(:inbound)
42
48
  if opts.key? :default
43
49
  hash_filter.optional { send(type_method, name, opts, &block) }
44
50
  else
@@ -65,6 +71,10 @@ module Hyperloop
65
71
  @hash_filter ||= Mutations::HashFilter.new
66
72
  end
67
73
 
74
+ def inbound_params
75
+ @inbound_params ||= Set.new
76
+ end
77
+
68
78
  def translate_args(*args, &block)
69
79
  name, opts = get_name_and_opts(*args)
70
80
  if opts.key?(:type)
@@ -115,6 +125,8 @@ module Hyperloop
115
125
  Class.new(superclass.params_wrapper).tap do |wrapper|
116
126
  hash_filter = superclass.params_wrapper.hash_filter
117
127
  wrapper.instance_variable_set('@hash_filter', hash_filter && hash_filter.dup)
128
+ inbound_params = superclass.params_wrapper.inbound_params
129
+ wrapper.instance_variable_set('@inbound_params', inbound_params && inbound_params.dup)
118
130
  end
119
131
  end
120
132
  end
@@ -101,7 +101,7 @@ module Hyperloop
101
101
  end
102
102
 
103
103
  class ControllerOp < ServerOp
104
- param :controller
104
+ inbound :controller
105
105
  alias pre_controller_op_method_missing method_missing
106
106
  def method_missing(name, *args, &block)
107
107
  if params.controller.respond_to? name
@@ -28,6 +28,10 @@ module Hyperloop
28
28
  end
29
29
  end
30
30
 
31
+ def self.connect_session
32
+ connect(['Hyperloop::Session', ClientDrivers.opts[:id].split('-').last])
33
+ end
34
+
31
35
  def self.action_cable_consumer
32
36
  ClientDrivers.opts[:action_cable_consumer]
33
37
  end
@@ -114,6 +118,7 @@ module Hyperloop
114
118
  end
115
119
  controller.session.delete 'hyperloop-dummy-init' unless controller.session.id
116
120
  id = "#{SecureRandom.uuid}-#{controller.session.id}"
121
+ auto_connections = Hyperloop::AutoConnect.channels(id, controller.acting_user)
117
122
  config_hash = {
118
123
  transport: Hyperloop.transport,
119
124
  id: id,
@@ -126,7 +131,7 @@ module Hyperloop
126
131
  channel: Hyperloop.channel,
127
132
  form_authenticity_token: controller.send(:form_authenticity_token),
128
133
  seconds_between_poll: Hyperloop.seconds_between_poll,
129
- auto_connect: Hyperloop::AutoConnect.channels(id, controller.acting_user)
134
+ auto_connect: auto_connections
130
135
  }
131
136
  path = ::Rails.application.routes.routes.detect do |route|
132
137
  # not sure why the second check is needed. It happens in the test app
@@ -171,7 +176,6 @@ module Hyperloop
171
176
  end
172
177
 
173
178
  if on_opal_client?
174
-
175
179
  if opts[:transport] == :pusher
176
180
 
177
181
  opts[:dispatch] = lambda do |data|
@@ -2,7 +2,8 @@ module Hyperloop
2
2
  module AutoCreate
3
3
  def needs_init?
4
4
  return false if Hyperloop.transport == :none
5
- return true unless connection.tables.include?(table_name)
5
+ return true if connection.respond_to?(:data_sources) && !connection.data_sources.include?(table_name)
6
+ return true if !connection.respond_to?(:data_sources) && !connection.tables.include?(table_name)
6
7
  return false unless Hyperloop.on_server?
7
8
  return true if defined?(Rails::Server)
8
9
  return true unless Connection.root_path
@@ -19,6 +19,7 @@ module Hyperloop
19
19
  config.after_initialize { Connection.build_tables }
20
20
  end
21
21
  Object.send(:remove_const, :Application) if @fake_application_defined
22
+ @fake_application_defined = false
22
23
  policy = begin
23
24
  Object.const_get 'ApplicationPolicy'
24
25
  rescue LoadError
@@ -61,6 +62,7 @@ module Hyperloop
61
62
  define_setting :opts, {}
62
63
  define_setting :channel_prefix, 'synchromesh'
63
64
  define_setting :client_logging, true
65
+ define_setting :connect_session, true
64
66
 
65
67
  def self.app_id
66
68
  opts[:app_id] || Pusher.app_id if transport == :pusher
@@ -42,6 +42,17 @@ module Hyperloop
42
42
  session.delete 'hyperloop-dummy-init' unless session.id
43
43
  end
44
44
 
45
+ def session_channel
46
+ "Hyperloop::Session-#{session.id}"
47
+ end
48
+
49
+ def regulate(channel)
50
+ unless channel == session_channel # "Hyperloop::Session-#{client_id.split('-').last}"
51
+ Hyperloop::InternalPolicy.regulate_connection(try(:acting_user), channel)
52
+ end
53
+ channel
54
+ end
55
+
45
56
  def channels(user = acting_user, session_id = session.id)
46
57
  Hyperloop::AutoConnect.channels(session_id, user)
47
58
  end
@@ -89,8 +100,7 @@ module Hyperloop
89
100
  end
90
101
 
91
102
  def subscribe
92
- channel = params[:channel].gsub('==', '::')
93
- Hyperloop::InternalPolicy.regulate_connection(try(:acting_user), channel)
103
+ channel = regulate params[:channel].gsub('==', '::')
94
104
  root_path = request.original_url.gsub(/hyperloop-subscribe.*$/, '')
95
105
  Hyperloop::Connection.open(channel, client_id, root_path)
96
106
  head :ok
@@ -105,8 +115,7 @@ module Hyperloop
105
115
  end
106
116
 
107
117
  def pusher_auth
108
- channel = params[:channel_name].gsub(/^#{Regexp.quote(Hyperloop.channel)}\-/,'').gsub('==', '::')
109
- Hyperloop::InternalPolicy.regulate_connection(acting_user, channel)
118
+ channel = regulate params[:channel_name].gsub(/^#{Regexp.quote(Hyperloop.channel)}\-/,'').gsub('==', '::')
110
119
  response = Hyperloop.pusher.authenticate(params[:channel_name], params[:socket_id])
111
120
  render json: response
112
121
  rescue Exception => e
@@ -114,8 +123,7 @@ module Hyperloop
114
123
  end
115
124
 
116
125
  def action_cable_auth
117
- channel = params[:channel_name].gsub(/^#{Regexp.quote(Hyperloop.channel)}\-/,'')
118
- Hyperloop::InternalPolicy.regulate_connection(acting_user, channel)
126
+ channel = regulate params[:channel_name].gsub(/^#{Regexp.quote(Hyperloop.channel)}\-/,'')
119
127
  salt = SecureRandom.hex
120
128
  authorization = Hyperloop.authorization(salt, channel, client_id)
121
129
  render json: {authorization: authorization, salt: salt}
@@ -296,11 +296,8 @@ module Hyperloop
296
296
  def self.channels(session, acting_user)
297
297
  channels = ClassConnectionRegulation.connections_for(acting_user, true) +
298
298
  InstanceConnectionRegulation.connections_for(acting_user, true)
299
- channels = channels.uniq
300
- channels.each do |channel|
301
- Connection.open(channel, session)
302
- end
303
- channels
299
+ channels << "Hyperloop::Session-#{session.split('-').last}" if Hyperloop.connect_session && session
300
+ channels.uniq.each { |channel| Connection.open(channel, session) }
304
301
  end
305
302
  end
306
303
 
@@ -1,5 +1,5 @@
1
1
  module Hyperloop
2
2
  class Operation
3
- VERSION = '0.5.11'
3
+ VERSION = '0.5.12'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyper-operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.11
4
+ version: 0.5.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - catmando
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-25 00:00:00.000000000 Z
11
+ date: 2017-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mutations
@@ -80,34 +80,6 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.3.0
83
- - !ruby/object:Gem::Dependency
84
- name: pusher
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: pusher-fake
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
83
  - !ruby/object:Gem::Dependency
112
84
  name: bundler
113
85
  requirement: !ruby/object:Gem::Requirement
@@ -234,6 +206,20 @@ dependencies:
234
206
  - - '='
235
207
  - !ruby/object:Gem::Version
236
208
  version: 1.3.10
209
+ - !ruby/object:Gem::Dependency
210
+ name: mysql2
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
237
223
  - !ruby/object:Gem::Dependency
238
224
  name: database_cleaner
239
225
  requirement: !ruby/object:Gem::Requirement
@@ -304,6 +290,48 @@ dependencies:
304
290
  - - ">="
305
291
  - !ruby/object:Gem::Version
306
292
  version: '0'
293
+ - !ruby/object:Gem::Dependency
294
+ name: pusher
295
+ requirement: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - ">="
298
+ - !ruby/object:Gem::Version
299
+ version: '0'
300
+ type: :development
301
+ prerelease: false
302
+ version_requirements: !ruby/object:Gem::Requirement
303
+ requirements:
304
+ - - ">="
305
+ - !ruby/object:Gem::Version
306
+ version: '0'
307
+ - !ruby/object:Gem::Dependency
308
+ name: pusher-fake
309
+ requirement: !ruby/object:Gem::Requirement
310
+ requirements:
311
+ - - ">="
312
+ - !ruby/object:Gem::Version
313
+ version: '0'
314
+ type: :development
315
+ prerelease: false
316
+ version_requirements: !ruby/object:Gem::Requirement
317
+ requirements:
318
+ - - ">="
319
+ - !ruby/object:Gem::Version
320
+ version: '0'
321
+ - !ruby/object:Gem::Dependency
322
+ name: timecop
323
+ requirement: !ruby/object:Gem::Requirement
324
+ requirements:
325
+ - - "~>"
326
+ - !ruby/object:Gem::Version
327
+ version: 0.8.1
328
+ type: :development
329
+ prerelease: false
330
+ version_requirements: !ruby/object:Gem::Requirement
331
+ requirements:
332
+ - - "~>"
333
+ - !ruby/object:Gem::Version
334
+ version: 0.8.1
307
335
  description:
308
336
  email:
309
337
  - mitch@catprint.com
@@ -313,6 +341,8 @@ extra_rdoc_files: []
313
341
  files:
314
342
  - ".gitignore"
315
343
  - CODE_OF_CONDUCT.md
344
+ - DOCS-POLICIES.md
345
+ - DOCS.md
316
346
  - Gemfile
317
347
  - LICENSE.txt
318
348
  - README.md
@@ -619,7 +649,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
619
649
  version: '0'
620
650
  requirements: []
621
651
  rubyforge_project:
622
- rubygems_version: 2.5.1
652
+ rubygems_version: 2.6.12
623
653
  signing_key:
624
654
  specification_version: 4
625
655
  summary: Compose your business logic into isomorphic commands that sanitize and validate