stimulus_reflex 1.0.2 → 1.1.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.
Potentially problematic release.
This version of stimulus_reflex might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +5 -5
- data/README.md +114 -12
- data/Rakefile +2 -0
- data/bin/standardize +1 -1
- data/lib/stimulus_reflex/channel.rb +25 -7
- data/lib/stimulus_reflex/dom_element.rb +18 -0
- data/lib/stimulus_reflex/reflex.rb +2 -0
- data/lib/stimulus_reflex/version.rb +3 -1
- data/lib/stimulus_reflex.rb +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 253dc2246ab12a13e75ea23f907375b011d3ef16fae1836638a81c00017f5eb1
|
4
|
+
data.tar.gz: f1a2a7e3555a9509f9a3a1fb1bdccb0ecd36fb806511302e7cc5f1fe18d7d2c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93a93f0ecf009492eeb422249814d1b9bfdd4de8592cac5e4d6feb029a670ea3dd6b15b156b11da564e4b4ec6453e97bdddccecdb8bd0df5c29c8d3b45efa264
|
7
|
+
data.tar.gz: be64d27ccfa1a7c8cec4781c199628af9e4ad345bbf0744fbc64f4bb9b6bb9de0de8fcdb413ad2fb58e666dcd7362198b45355d64e8f25dd87f882fd9f942fef
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
stimulus_reflex (1.0
|
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.
|
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.
|
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.
|
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.
|
165
|
+
zeitwerk (2.1.10)
|
166
166
|
|
167
167
|
PLATFORMS
|
168
168
|
ruby
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
[](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
|
2
2
|
[](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
|
-
|
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
|
-
|
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
data/bin/standardize
CHANGED
@@ -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 "
|
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 "
|
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
|
-
|
42
|
-
|
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
|
-
|
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
|
data/lib/stimulus_reflex.rb
CHANGED
@@ -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
|
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-
|
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
|