stimulus_reflex 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stimulus_reflex might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6798571d8f8229083855114f5f499414f308a47e03c438f1b74b5eb534acd78f
4
- data.tar.gz: 62e2d714b2ae14c16bf4435665d339717d9fa99330d3eb604fa6720c15f64f80
3
+ metadata.gz: 253dc2246ab12a13e75ea23f907375b011d3ef16fae1836638a81c00017f5eb1
4
+ data.tar.gz: f1a2a7e3555a9509f9a3a1fb1bdccb0ecd36fb806511302e7cc5f1fe18d7d2c3
5
5
  SHA512:
6
- metadata.gz: 2d22087e7519727c787770fb971aa510d2480a5b45e00efa78eb708adcc69d89cf085b3fad6544c9a46bb183240ea452ded9ce665495ca7f5d47bcc021c8a7e0
7
- data.tar.gz: 3b0aaf7d1c98ba7281f24f2d96fb1d043e297847837c2ad38028bac114c7ed7fe80c929e0c58491b646533f8d4958921e8e1483d5bc320c4d04d3034ec2e53aa
6
+ metadata.gz: 93a93f0ecf009492eeb422249814d1b9bfdd4de8592cac5e4d6feb029a670ea3dd6b15b156b11da564e4b4ec6453e97bdddccecdb8bd0df5c29c8d3b45efa264
7
+ data.tar.gz: be64d27ccfa1a7c8cec4781c199628af9e4ad345bbf0744fbc64f4bb9b6bb9de0de8fcdb413ad2fb58e666dcd7362198b45355d64e8f25dd87f882fd9f942fef
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stimulus_reflex (1.0.2)
4
+ stimulus_reflex (1.1.0)
5
5
  cable_ready (>= 4.0.3)
6
6
  nokogiri
7
7
  rack
@@ -90,11 +90,11 @@ GEM
90
90
  mini_mime (1.0.2)
91
91
  mini_portile2 (2.4.0)
92
92
  minitest (5.11.3)
93
- nio4r (2.4.0)
93
+ nio4r (2.5.1)
94
94
  nokogiri (1.10.4)
95
95
  mini_portile2 (~> 2.4.0)
96
96
  parallel (1.17.0)
97
- parser (2.6.3.0)
97
+ parser (2.6.4.0)
98
98
  ast (~> 2.4.0)
99
99
  pry (0.12.2)
100
100
  coderay (~> 1.1.0)
@@ -149,7 +149,7 @@ GEM
149
149
  actionpack (>= 4.0)
150
150
  activesupport (>= 4.0)
151
151
  sprockets (>= 3.0.0)
152
- standard (0.1.2)
152
+ standard (0.1.3)
153
153
  rubocop (~> 0.72.0)
154
154
  rubocop-performance (~> 1.4.0)
155
155
  standardrb (1.0.0)
@@ -162,7 +162,7 @@ GEM
162
162
  websocket-driver (0.7.1)
163
163
  websocket-extensions (>= 0.1.0)
164
164
  websocket-extensions (0.1.4)
165
- zeitwerk (2.1.9)
165
+ zeitwerk (2.1.10)
166
166
 
167
167
  PLATFORMS
168
168
  ruby
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
- [![Lines of Code](http://img.shields.io/badge/lines_of_code-159-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
1
+ [![Lines of Code](http://img.shields.io/badge/lines_of_code-203-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
2
2
  [![Maintainability](https://api.codeclimate.com/v1/badges/2b24fdbd1ae37a24bedb/maintainability)](https://codeclimate.com/github/hopsoft/stimulus_reflex/maintainability)
3
3
 
4
4
  # StimulusReflex
5
5
 
6
+ _reflex_ - an action that is performed as a response to a stimulus
7
+
6
8
  ### Build reactive [Single Page Applications (SPAs)](https://en.wikipedia.org/wiki/Single-page_application) with [Rails](https://rubyonrails.org) and [Stimulus](https://stimulusjs.org)
7
9
 
8
10
  This project supports building [reactive applications](https://en.wikipedia.org/wiki/Reactive_programming)
@@ -11,19 +13,51 @@ It's designed to work perfectly with [server rendered HTML](https://guides.rubyo
11
13
  [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching),
12
14
  [Stimulus](https://stimulusjs.org), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc...
13
15
 
14
-
15
16
  __No need for a complex front-end framework. No need to grow your team or duplicate your efforts.__
16
17
 
17
- ---
18
-
19
- > The lifecycle of a "modern" SPA app is so convoluted, it requires a team to build and support.
20
- > The wire size and computation demands of these heavy client sites frequently run slower than the server-rendered pages that they replaced.
21
- > With Stimulus Reflex, a Rails developer can build Single Page Applications without the need for client rendering or heavy JS frameworks.
22
-
23
- ---
24
-
25
18
  _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
26
19
 
20
+ ## Table of Contents
21
+
22
+ <!-- toc -->
23
+
24
+ - [Before you Begin](#before-you-begin)
25
+ - [How it Works](#how-it-works)
26
+ - [Setup](#setup)
27
+ * [JavaScript](#javascript)
28
+ * [Gemfile](#gemfile)
29
+ - [Basic Usage](#basic-usage)
30
+ * [app/views/pages/example.html.erb](#appviewspagesexamplehtmlerb)
31
+ * [app/javascript/controllers/example.js](#appjavascriptcontrollersexamplejs)
32
+ * [app/reflexes/example_reflex.rb](#appreflexesexample_reflexrb)
33
+ - [Advanced Usage](#advanced-usage)
34
+ * [Reflex Methods](#reflex-methods)
35
+ + [The `options` Keyword Argument](#the-options-keyword-argument)
36
+ * [ActionCable](#actioncable)
37
+ + [Performance](#performance)
38
+ + [ActionCable Rooms](#actioncable-rooms)
39
+ * [Render Delay](#render-delay)
40
+ - [Demo Applications](#demo-applications)
41
+ - [Contributing](#contributing)
42
+ * [Coding Standards](#coding-standards)
43
+ * [Releasing](#releasing)
44
+
45
+ <!-- tocstop -->
46
+
47
+ ## Before you Begin
48
+
49
+ StimulusReflex provides functionality similar to what can already be achieved with Rails by combining
50
+ [UJS remote elements](https://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements)
51
+ , [Stimulus](https://stimulusjs.org), and [Turbolinks](https://github.com/turbolinks/turbolinks).
52
+ _Consider building with standard Rails tooling before introducing StimulusReflex._
53
+ _Check out the [Stimulus TodoMVC](https://github.com/hopsoft/stimulus_todomvc) example if you are unsure how to accomplish this._
54
+
55
+ StimulusReflex offers 3 primary benefits over the traditional Rails HTTP request/response cycle.
56
+
57
+ 1. __Communication happens on the ActionCable web socket__ _- saves time by avoiding the overhead of establishishing traditional HTTP connections_
58
+ 1. __The controller action is invoked directly__ _- skips framework overhead such as the middleware chain, etc..._
59
+ 1. __DOM diffing is used to update the page__ _- provides faster rendering and less jitter_
60
+
27
61
  ## How it Works
28
62
 
29
63
  1. Render a standard Rails view template
@@ -100,12 +134,64 @@ The following happens after the `StimulusReflex::Reflex` method call finishes.
100
134
 
101
135
  ## Advanced Usage
102
136
 
137
+ ### Reflex Methods
138
+
139
+ #### The `options` Keyword Argument
140
+
141
+ Reflex methods support an _optional_ `options` keyword argument.
142
+
143
+ - This is the only supported keyword argument.
144
+ - It must appear after ordinal arguments.
145
+
146
+ ```ruby
147
+ class ExampleReflex < StimulusReflex::Reflex
148
+ def work(options: {})
149
+ # ...
150
+ end
151
+
152
+ def other_work(value, options: {})
153
+ # ...
154
+ end
155
+ end
156
+ ```
157
+
158
+ The `options` value contains all of the Stimulus controller's
159
+ [DOM element attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) as well as other properties like `checked` and `value`.
160
+ _Most of the values will be strings._
161
+ Here's an example:
162
+
163
+ ```html
164
+ <checkbox checked label="Example" data-controller="checkbox" data-value="123" />
165
+ ```
166
+
167
+ The markup above produces the following behavior in a reflex method.
168
+
169
+ ```ruby
170
+ class ExampleReflex < StimulusReflex::Reflex
171
+ def work(options: {})
172
+ options[:checked] # => true
173
+ options[:label] # => "Example"
174
+ options["data-controller"] # => "checkbox"
175
+ options["data-value"] # => "123"
176
+ options.dataset[:controller] # => "checkbox"
177
+ options.dataset[:value] # => "123"
178
+ end
179
+ end
180
+ ```
181
+
182
+ - `options[:checked]` holds a boolean
183
+ - `options[:selected]` holds a boolean
184
+ - `options[:value]` holds the [DOM element's value](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#value)
185
+ - `select` elements assign `options[:value]` to their selected option's value
186
+ - `select` elements with _multiselect_ enabled assign `options[:values]` to their selected options values
187
+ - All other values stored in `options` are extracted from the DOM element's attributes
188
+
103
189
  ### ActionCable
104
190
 
105
191
  StimulusReflex will use the ActionCable defaults of `window.App` and `App.cable` if they exist.
106
192
  If these defaults do not exist, StimulusReflex will establish a new socket connection.
107
193
 
108
- ### Performance
194
+ #### Performance
109
195
 
110
196
  ActionCable emits verbose log messages. Disabling ActionCable logs may improve performance.
111
197
 
@@ -115,7 +201,7 @@ ActionCable emits verbose log messages. Disabling ActionCable logs may improve p
115
201
  ActionCable.server.config.logger = Logger.new(nil)
116
202
  ```
117
203
 
118
- ### ActionCable Rooms
204
+ #### ActionCable Rooms
119
205
 
120
206
  You may find the need to restrict notifications to a specific room.
121
207
  This can be accomplished by setting the `data-room` attribute on the StimulusController element.
@@ -151,6 +237,22 @@ Building apps with StimulusReflex should evoke your memories of the original [Ra
151
237
 
152
238
  ## Contributing
153
239
 
240
+ ### Coding Standards
241
+
154
242
  This project uses [Standard](https://github.com/testdouble/standard)
155
243
  and [Prettier](https://github.com/prettier/prettier) to minimize bike shedding related to code formatting.
156
244
  Please run `./bin/standardize` prior submitting pull requests.
245
+
246
+ ### Releasing
247
+
248
+ 1. Bump version number at `lib/stimulus_reflex/version.rb`
249
+ 1. Push changes to GitHub
250
+ 1. Run `rake release`
251
+ 1. Run `yarn publish`
252
+ 1. Assign same version number to the JavaScript package
253
+ 1. Push changes to GitHub
254
+ 1. Push tags to GitHub
255
+
256
+ ```
257
+ git push --tags
258
+ ```
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  task default: :spec
data/bin/standardize CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/bin/bash
2
2
 
3
3
  bundle exec standardrb --fix
4
- prettier --write javascript/stimulus_reflex.js
4
+ cd ./javascript && yarn run prettier --write stimulus_reflex.js
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class StimulusReflex::Channel < ActionCable::Channel::Base
2
4
  include CableReady::Broadcaster
3
5
 
@@ -20,28 +22,44 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
20
22
  reflex_name, method_name = target.split("#")
21
23
  reflex_name = reflex_name.classify
22
24
  arguments = data["args"] || []
25
+ options = StimulusReflex::DomElement.new(data["attrs"])
23
26
 
24
27
  begin
25
28
  reflex = reflex_name.constantize.new(self, url: url)
26
- delegate_call_to_reflex reflex, method_name, arguments
29
+ delegate_call_to_reflex reflex, method_name, arguments, options
27
30
  rescue => invoke_error
28
- logger.error "StimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}"
31
+ logger.error "\e[31mStimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}\e[0m"
29
32
  end
30
33
 
31
34
  begin
32
35
  render_page_and_broadcast_morph url, reflex
33
36
  rescue => render_error
34
- logger.error "StimulusReflex::Channel Failed to rerender #{url} #{render_error}"
37
+ logger.error "\e[31mStimulusReflex::Channel Failed to rerender #{url} #{render_error}\e[0m"
35
38
  end
36
39
  end
37
40
 
38
41
  private
39
42
 
40
- def delegate_call_to_reflex(reflex, method_name, arguments = [])
41
- if reflex.method(method_name).arity != 0
42
- reflex.send method_name, *arguments
43
+ def delegate_call_to_reflex(reflex, method_name, arguments = [], options = {})
44
+ method = reflex.method(method_name)
45
+ required_params = method.parameters.select { |(kind, _)| kind == :req }
46
+ optional_params = method.parameters.select { |(kind, _)| kind == :opt }
47
+ accepts_options_kwarg = method.parameters.select { |(kind, name)| name == :options && kind.to_s.start_with?("key") }.size > 0
48
+
49
+ if arguments.size == 0 && required_params.size == 0
50
+ if accepts_options_kwarg
51
+ reflex.public_send method_name, {options: options}
52
+ else
53
+ reflex.public_send method_name
54
+ end
55
+ elsif arguments.size >= required_params.size && arguments.size <= required_params.size + optional_params.size
56
+ if accepts_options_kwarg
57
+ reflex.public_send method_name, *arguments, {options: options}
58
+ else
59
+ reflex.public_send method_name, *arguments
60
+ end
43
61
  else
44
- reflex.send method_name
62
+ raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{required_params.inspect}, optional #{optional_params.inspect})")
45
63
  end
46
64
  end
47
65
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class StimulusReflex::DomElement
4
+ attr_reader :attributes
5
+
6
+ delegate :[], to: :"@attributes"
7
+
8
+ def initialize(attrs = {})
9
+ @attributes = HashWithIndifferentAccess.new(attrs || {}).freeze
10
+ end
11
+
12
+ def dataset
13
+ @dataset ||= attributes.each_with_object(HashWithIndifferentAccess.new) { |(key, value), memo|
14
+ next unless key.start_with?("data-")
15
+ memo[key.delete_prefix("data-")] = value
16
+ }.freeze
17
+ end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class StimulusReflex::Reflex
2
4
  attr_reader :channel, :url
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StimulusReflex
2
- VERSION = "1.0.2"
4
+ VERSION = "1.1.0"
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "uri"
2
4
  require "rack"
3
5
  require "rails/engine"
@@ -8,6 +10,7 @@ require "nokogiri"
8
10
  require "cable_ready"
9
11
  require "stimulus_reflex/version"
10
12
  require "stimulus_reflex/reflex"
13
+ require "stimulus_reflex/dom_element"
11
14
  require "stimulus_reflex/channel"
12
15
 
13
16
  module StimulusReflex
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus_reflex
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Hopkins
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-08-17 00:00:00.000000000 Z
12
+ date: 2019-09-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -156,6 +156,7 @@ files:
156
156
  - bin/standardize
157
157
  - lib/stimulus_reflex.rb
158
158
  - lib/stimulus_reflex/channel.rb
159
+ - lib/stimulus_reflex/dom_element.rb
159
160
  - lib/stimulus_reflex/reflex.rb
160
161
  - lib/stimulus_reflex/version.rb
161
162
  homepage: https://github.com/hopsoft/stimulus_reflex