stimulus_reflex 1.1.1 → 2.1.1

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: ce2617cefcb188998c2f9aca1a440bd2501839a699166cdfa32fba44741af5f5
4
- data.tar.gz: a486389eef17cfa47e8fefef2256cd72a2aff25c1d6ce5713cc49d444565f787
3
+ metadata.gz: 8966252da698bc7f603c5899b1f2a8b38aa3d8af53d20188eba815a293b1388d
4
+ data.tar.gz: 4ca61b2211ff6cbafb84ccf59ac9cfdb6803bfb5dcf38f56782ec8babb307e4c
5
5
  SHA512:
6
- metadata.gz: 36f7b68e56c6446b5125d984378f24207bec848fdfeb99365b99dcac3f9b725e20a99fbd093740e22abc8c8d6fae4b16bd9c470d475289adcd25bb4b177a5563
7
- data.tar.gz: ed8f1e225df23c5b949f2c1f6a4f743521f7b6118f621808b19f46d6716fe812b7c6d475149972ad655737806c3612768d9001cc1f6619b41e2732543a6f6fb4
6
+ metadata.gz: 6b21d5c651bd372d5cdd2ddc2928f8e15f118121a430db8fc0bf609585a2fc1a02d5e19a5decb504d5e262aae36c89b1b706093a4aa9eadc9e69886b56da5bda
7
+ data.tar.gz: 19cea4683e33acfd2abe563e4c27c37a7335d9ce32b543e59b606d7d58a6e5c58d819fac0f4eaf1cc9c9bee4524c01a8b00a13a5c9d329ac4b403ee980615f8f
@@ -0,0 +1,76 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, sex characteristics, gender identity and expression,
9
+ level of experience, education, socio-economic status, nationality, personal
10
+ appearance, race, religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ - Using welcoming and inclusive language
18
+ - Being respectful of differing viewpoints and experiences
19
+ - Gracefully accepting constructive criticism
20
+ - Focusing on what is best for the community
21
+ - Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ - The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ - Trolling, insulting/derogatory comments, and personal or political attacks
28
+ - Public or private harassment
29
+ - Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at natehop@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
+
73
+ [homepage]: https://www.contributor-covenant.org
74
+
75
+ For answers to common questions about this code of conduct, see
76
+ https://www.contributor-covenant.org/faq
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stimulus_reflex (1.1.1)
5
- cable_ready (>= 4.0.3)
4
+ stimulus_reflex (2.1.1)
5
+ cable_ready (>= 4.0.7)
6
6
  nokogiri
7
7
  rack
8
8
  rails (>= 5.2)
@@ -67,18 +67,18 @@ GEM
67
67
  zeitwerk (~> 2.1, >= 2.1.8)
68
68
  ast (2.4.0)
69
69
  builder (3.2.3)
70
- cable_ready (4.0.3)
70
+ cable_ready (4.0.7)
71
71
  rails (>= 5.2)
72
72
  coderay (1.1.2)
73
73
  concurrent-ruby (1.1.5)
74
74
  crass (1.0.4)
75
- erubi (1.8.0)
75
+ erubi (1.9.0)
76
76
  globalid (0.4.2)
77
77
  activesupport (>= 4.2.0)
78
- i18n (1.6.0)
78
+ i18n (1.7.0)
79
79
  concurrent-ruby (~> 1.0)
80
80
  jaro_winkler (1.5.3)
81
- loofah (2.2.3)
81
+ loofah (2.3.0)
82
82
  crass (~> 1.0.2)
83
83
  nokogiri (>= 1.5.9)
84
84
  mail (2.7.1)
@@ -89,12 +89,12 @@ GEM
89
89
  mimemagic (0.3.3)
90
90
  mini_mime (1.0.2)
91
91
  mini_portile2 (2.4.0)
92
- minitest (5.11.3)
93
- nio4r (2.5.1)
92
+ minitest (5.12.2)
93
+ nio4r (2.5.2)
94
94
  nokogiri (1.10.4)
95
95
  mini_portile2 (~> 2.4.0)
96
- parallel (1.17.0)
97
- parser (2.6.4.0)
96
+ parallel (1.18.0)
97
+ parser (2.6.5.0)
98
98
  ast (~> 2.4.0)
99
99
  pry (0.12.2)
100
100
  coderay (~> 1.1.0)
@@ -122,8 +122,8 @@ GEM
122
122
  rails-dom-testing (2.0.3)
123
123
  activesupport (>= 4.2.0)
124
124
  nokogiri (>= 1.6)
125
- rails-html-sanitizer (1.2.0)
126
- loofah (~> 2.2, >= 2.2.2)
125
+ rails-html-sanitizer (1.3.0)
126
+ loofah (~> 2.3)
127
127
  railties (6.0.0)
128
128
  actionpack (= 6.0.0)
129
129
  activesupport (= 6.0.0)
@@ -131,7 +131,7 @@ GEM
131
131
  rake (>= 0.8.7)
132
132
  thor (>= 0.20.3, < 2.0)
133
133
  rainbow (3.0.0)
134
- rake (12.3.3)
134
+ rake (13.0.0)
135
135
  rubocop (0.72.0)
136
136
  jaro_winkler (~> 1.5.1)
137
137
  parallel (~> 1.10)
@@ -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.3)
152
+ standard (0.1.4)
153
153
  rubocop (~> 0.72.0)
154
154
  rubocop-performance (~> 1.4.0)
155
155
  standardrb (1.0.0)
data/README.md CHANGED
@@ -1,259 +1,45 @@
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/)
1
+ [![Lines of Code](http://img.shields.io/badge/lines_of_code-466-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
+ ![Prettier-Standard](https://github.com/hopsoft/stimulus_reflex/workflows/Prettier-Standard/badge.svg)
4
+ ![StandardRB](https://github.com/hopsoft/stimulus_reflex/workflows/StandardRB/badge.svg)
5
+ ![Tests](https://github.com/hopsoft/stimulus_reflex/workflows/Tests/badge.svg)
3
6
 
4
7
  # StimulusReflex
5
8
 
6
9
  _reflex_ - an action that is performed as a response to a stimulus
7
10
 
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)
9
-
10
- This project supports building [reactive applications](https://en.wikipedia.org/wiki/Reactive_programming)
11
- with the Rails tooling you already know and love.
12
- It's designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html),
13
- [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching),
14
- [Stimulus](https://stimulusjs.org), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc...
15
-
16
- __No need for a complex front-end framework. No need to grow your team or duplicate your efforts.__
11
+ **Build reactive applications with the Rails tooling you already know and love.** StimulusReflex is designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html), [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching), [Stimulus](https://stimulusjs.org/), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc... and strives to live up to the vision outlined in [The Rails Doctrine](https://rubyonrails.org/doctrine/).
17
12
 
18
13
  _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
19
14
 
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
-
61
- ## How it Works
62
-
63
- 1. Render a standard Rails view template
64
- 1. Use [Stimulus](https://stimulusjs.org) and [ActionCable](https://edgeguides.rubyonrails.org/action_cable_overview.html) to invoke a method on the server
65
- 1. Watch the page automatically render updates via fast [DOM diffing](https://github.com/patrick-steele-idem/morphdom)
66
- 1. That's it...
67
-
68
- __Yes, it really is that simple.__
69
- There are no hidden gotchas.
70
-
71
- ![How it Works](https://raw.githubusercontent.com/hopsoft/stimulus_reflex/master/docs/diagram.png)
72
-
73
- ## Setup
74
-
75
- ### JavaScript
76
-
77
- ```
78
- yarn add stimulus_reflex
79
- ```
80
-
81
- ### Gemfile
82
-
83
- ```ruby
84
- gem "stimulus_reflex"
85
- ```
86
-
87
- ## Basic Usage
88
-
89
- ### app/views/pages/example.html.erb
90
-
91
- ```erb
92
- <head></head>
93
- <body>
94
- <a href="#" data-controller="example" data-action="click->example#increment">
95
- Increment <%= @count.to_i %>
96
- </a>
97
- </body>
98
- </html>
99
- ```
100
-
101
- ### app/javascript/controllers/example.js
102
-
103
- ```javascript
104
- import { Controller } from "stimulus"
105
- import StimulusReflex from "stimulus_reflex"
106
-
107
- export default class extends Controller {
108
- connect() {
109
- StimulusReflex.register(this);
110
- }
111
-
112
- increment() {
113
- // trigger a server-side reflex and a client-side page update
114
- this.stimulate('ExampleReflex#increment', 1);
115
- }
116
- }
117
- ```
118
-
119
- ### app/reflexes/example_reflex.rb
120
-
121
- ```ruby
122
- class ExampleReflex < StimulusReflex::Reflex
123
- def increment(step = 1)
124
- @count = @count.to_i + step
125
- end
126
- end
127
- ```
128
-
129
- The following happens after the `StimulusReflex::Reflex` method call finishes.
130
-
131
- 1. The page that triggered the reflex is re-rerendered. _Instance variables created in the reflex are available to both the controller and view templates._
132
- 2. The re-rendered HTML is sent to the client over the ActionCable socket.
133
- 3. The page is updated via fast DOM diffing courtesy of morphdom. _While future versions of StimulusReflex might support more granular updates, today the entire body is re-rendered and sent over the socket._
134
-
135
- ## Advanced Usage
136
-
137
- ### Reflex Methods
15
+ ## Docs
138
16
 
139
- #### The `options` Keyword Argument
17
+ - [Official Documentation](https://docs.stimulusreflex.com)
18
+ - [Documentation Source Code](https://github.com/hopsoft/stimulus_reflex/tree/master/docs)
140
19
 
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
-
189
- ### ActionCable
190
-
191
- StimulusReflex will use the ActionCable defaults of `window.App` and `App.cable` if they exist.
192
- If these defaults do not exist, StimulusReflex will establish a new socket connection.
193
-
194
- #### Performance
195
-
196
- ActionCable emits verbose log messages. Disabling ActionCable logs may improve performance.
197
-
198
- ```ruby
199
- # config/application.rb
200
-
201
- ActionCable.server.config.logger = Logger.new(nil)
202
- ```
203
-
204
- #### ActionCable Rooms
205
-
206
- You may find the need to restrict notifications to a specific room.
207
- This can be accomplished by setting the `data-room` attribute on the StimulusController element.
208
-
209
- ```erb
210
- <a href="#" data-controller="example" data-action="click->example#increment" data-room="12345">
211
- ```
212
-
213
- ### Render Delay
214
-
215
- An attempt is made to reduce repaint/reflow jitter when users trigger lots of updates.
216
-
217
- You can control how long to wait _(think debounce)_ prior to updating the page.
218
- Simply set the `renderDelay` _(milliseconds)_ option when registering the controller.
219
-
220
- ```javascript
221
- export default class extends Controller {
222
- connect() {
223
- StimulusReflex.register(this, {renderDelay: 200});
224
- }
225
- }
226
- ```
227
-
228
- The default value is `25`.
229
-
230
- ## Demo Applications
231
-
232
- Building apps with StimulusReflex should evoke your memories of the original [Rails demo video](https://www.youtube.com/watch?v=Gzj723LkRJY).
233
-
234
- > Look at all the things I'm **not** doing. -DHH
20
+ ## Contributing
235
21
 
236
- - [TodoMVC](https://github.com/hopsoft/stimulus_reflex_todomvc)
22
+ ### Code of Conduct
237
23
 
238
- ## Contributing
24
+ Everyone interacting with StimulusReflex is expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md)
239
25
 
240
26
  ### Coding Standards
241
27
 
242
28
  This project uses [Standard](https://github.com/testdouble/standard)
243
- and [Prettier](https://github.com/prettier/prettier) to minimize bike shedding related to code formatting.
29
+ and [Prettier-Standard](https://github.com/sheerun/prettier-standard) to minimize bike shedding related to code formatting.
30
+
244
31
  Please run `./bin/standardize` prior submitting pull requests.
245
32
 
33
+ View the [wiki](https://github.com/hopsoft/stimulus_reflex/wiki/Editor-Configuration) to see recommendations for configuring your editor to work best with the project.
34
+
246
35
  ### Releasing
247
36
 
248
37
  1. Bump version number at `lib/stimulus_reflex/version.rb`
249
38
  1. Run `rake build`
250
39
  1. Run `rake release`
251
40
  1. Change directories `cd ./javascript`
252
- 1. Run `yarn publish`
253
- 1. Assign same version number to the JavaScript package
254
- 1. Push changes to GitHub
255
- 1. Push tags to GitHub
41
+ 1. Run `yarn publish` - NOTE: this will throw a fatal error because the tag already exists but the package will still publish
42
+
43
+ ## License
256
44
 
257
- ```
258
- git push --tags
259
- ```
45
+ StimulusReflex is released under the [MIT License](LICENSE.txt).
data/Rakefile CHANGED
@@ -1,4 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: :spec
4
+
5
+ task default: [:test]
6
+
7
+ task :test do
8
+ exec "cd javascript && yarn run test"
9
+ end
data/bin/loc ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ cloc --exclude-dir=node_modules,test --include-ext=rb,js .
data/bin/standardize CHANGED
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
 
3
3
  bundle exec standardrb --fix
4
- cd ./javascript && yarn run prettier --write stimulus_reflex.js
4
+ cd ./javascript && yarn run prettier-standard stimulus_reflex.js test/*.js
@@ -10,7 +10,7 @@ require "nokogiri"
10
10
  require "cable_ready"
11
11
  require "stimulus_reflex/version"
12
12
  require "stimulus_reflex/reflex"
13
- require "stimulus_reflex/dom_element"
13
+ require "stimulus_reflex/element"
14
14
  require "stimulus_reflex/channel"
15
15
 
16
16
  module StimulusReflex
@@ -18,54 +18,53 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
18
18
 
19
19
  def receive(data)
20
20
  url = data["url"].to_s
21
+ selectors = (data["selectors"] || []).select(&:present?)
22
+ selectors = ["body"] if selectors.blank?
21
23
  target = data["target"].to_s
22
24
  reflex_name, method_name = target.split("#")
23
25
  reflex_name = reflex_name.classify
24
26
  arguments = data["args"] || []
25
- options = StimulusReflex::DomElement.new(data["attrs"])
27
+ element = StimulusReflex::Element.new(data["attrs"])
26
28
 
27
29
  begin
28
- reflex = reflex_name.constantize.new(self, url: url)
29
- delegate_call_to_reflex reflex, method_name, arguments, options
30
+ reflex_class = reflex_name.constantize
31
+ raise ArgumentError.new("#{reflex_name} is not a StimulusReflex::Reflex") unless is_reflex?(reflex_class)
32
+ reflex = reflex_class.new(self, url: url, element: element, selectors: selectors)
33
+ delegate_call_to_reflex reflex, method_name, arguments
30
34
  rescue => invoke_error
31
- logger.error "\e[31mStimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}\e[0m"
35
+ return broadcast_error("StimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}", data)
32
36
  end
33
37
 
34
38
  begin
35
- render_page_and_broadcast_morph url, reflex
39
+ render_page_and_broadcast_morph url, reflex, selectors, data
36
40
  rescue => render_error
37
- logger.error "\e[31mStimulusReflex::Channel Failed to rerender #{url} #{render_error}\e[0m"
41
+ broadcast_error "StimulusReflex::Channel Failed to re-render #{url} #{render_error}", data
38
42
  end
39
43
  end
40
44
 
41
45
  private
42
46
 
43
- def delegate_call_to_reflex(reflex, method_name, arguments = [], options = {})
47
+ def is_reflex?(reflex_class)
48
+ reflex_class.ancestors.include? StimulusReflex::Reflex
49
+ end
50
+
51
+ def delegate_call_to_reflex(reflex, method_name, arguments = [])
44
52
  method = reflex.method(method_name)
45
53
  required_params = method.parameters.select { |(kind, _)| kind == :req }
46
54
  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
55
 
49
56
  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
57
+ reflex.public_send method_name
55
58
  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
59
+ reflex.public_send method_name, *arguments
61
60
  else
62
61
  raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{required_params.inspect}, optional #{optional_params.inspect})")
63
62
  end
64
63
  end
65
64
 
66
- def render_page_and_broadcast_morph(url, reflex)
65
+ def render_page_and_broadcast_morph(url, reflex, selectors, data = {})
67
66
  html = render_page(url, reflex)
68
- broadcast_morph url, html if html.present?
67
+ broadcast_morphs selectors, data, html if html.present?
69
68
  end
70
69
 
71
70
  def render_page(url, reflex)
@@ -99,14 +98,28 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
99
98
  controller.response.body
100
99
  end
101
100
 
102
- def broadcast_morph(url, html)
103
- html = extract_body_html(html)
104
- cable_ready[stream_name].morph selector: "body", html: html, children_only: true
101
+ def broadcast_morphs(selectors, data, html)
102
+ document = Nokogiri::HTML(html)
103
+ selectors.each do |selector|
104
+ match = document.css(selector)
105
+ next if match.blank?
106
+ cable_ready[stream_name].morph(
107
+ selector: selector,
108
+ html: match.inner_html,
109
+ children_only: true,
110
+ permanent_attribute_name: "data-reflex-permanent",
111
+ stimulus_reflex: data
112
+ )
113
+ end
105
114
  cable_ready.broadcast
106
115
  end
107
116
 
108
- def extract_body_html(html)
109
- doc = Nokogiri::HTML(html)
110
- doc.css("body").to_s
117
+ def broadcast_error(message, data = {})
118
+ logger.error "\e[31m#{message}\e[0m"
119
+ cable_ready[stream_name].dispatch_event(
120
+ name: "stimulus-reflex:500",
121
+ detail: {stimulus_reflex: data.merge(error: message)}
122
+ )
123
+ cable_ready.broadcast
111
124
  end
112
125
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class StimulusReflex::DomElement
3
+ class StimulusReflex::Element
4
4
  attr_reader :attributes
5
5
 
6
6
  delegate :[], to: :"@attributes"
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class StimulusReflex::Reflex
4
- attr_reader :channel, :url
4
+ attr_reader :channel, :url, :element, :selectors
5
5
 
6
6
  delegate :connection, to: :channel
7
7
  delegate :session, to: :request
8
8
 
9
- def initialize(channel, url: nil)
9
+ def initialize(channel, url: nil, element: nil, selectors: [])
10
10
  @channel = channel
11
11
  @url = url
12
+ @element = element
13
+ @selectors = selectors
12
14
  end
13
15
 
14
16
  def request
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "1.1.1"
4
+ VERSION = "2.1.1"
5
5
  end
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.1.1
4
+ version: 2.1.1
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-09-09 00:00:00.000000000 Z
12
+ date: 2019-10-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 4.0.3
62
+ version: 4.0.7
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 4.0.3
69
+ version: 4.0.7
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: bundler
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -145,18 +145,19 @@ executables: []
145
145
  extensions: []
146
146
  extra_rdoc_files: []
147
147
  files:
148
+ - CODE_OF_CONDUCT.md
148
149
  - Gemfile
149
150
  - Gemfile.lock
150
151
  - LICENSE.txt
151
152
  - README.md
152
- - README.md.orig
153
153
  - Rakefile
154
154
  - bin/console
155
+ - bin/loc
155
156
  - bin/setup
156
157
  - bin/standardize
157
158
  - lib/stimulus_reflex.rb
158
159
  - lib/stimulus_reflex/channel.rb
159
- - lib/stimulus_reflex/dom_element.rb
160
+ - lib/stimulus_reflex/element.rb
160
161
  - lib/stimulus_reflex/reflex.rb
161
162
  - lib/stimulus_reflex/version.rb
162
163
  homepage: https://github.com/hopsoft/stimulus_reflex
data/README.md.orig DELETED
@@ -1,159 +0,0 @@
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/)
2
- [![Maintainability](https://api.codeclimate.com/v1/badges/2b24fdbd1ae37a24bedb/maintainability)](https://codeclimate.com/github/hopsoft/stimulus_reflex/maintainability)
3
-
4
- # StimulusReflex
5
-
6
- ### 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
-
8
- This project supports building [reactive applications](https://en.wikipedia.org/wiki/Reactive_programming)
9
- with the Rails tooling you already know and love.
10
- It's designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html),
11
- [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching),
12
- [Stimulus](https://stimulusjs.org), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc...
13
-
14
-
15
- __No need for a complex front-end framework. No need to grow your team or duplicate your efforts.__
16
-
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
- _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
26
-
27
- ## How it Works
28
-
29
- 1. Render a standard Rails view template
30
- 1. Use [Stimulus](https://stimulusjs.org) and [ActionCable](https://edgeguides.rubyonrails.org/action_cable_overview.html) to invoke a method on the server
31
- 1. Watch the page automatically render updates via fast [DOM diffing](https://github.com/patrick-steele-idem/morphdom)
32
- 1. That's it...
33
-
34
- __Yes, it really is that simple.__
35
- There are no hidden gotchas.
36
-
37
- ![How it Works](https://raw.githubusercontent.com/hopsoft/stimulus_reflex/master/docs/diagram.png)
38
-
39
- ## Setup
40
-
41
- ### JavaScript
42
-
43
- ```
44
- yarn add stimulus_reflex
45
- ```
46
-
47
- ### Gemfile
48
-
49
- ```ruby
50
- gem "stimulus_reflex"
51
- ```
52
-
53
- ## Basic Usage
54
-
55
- ### app/views/pages/example.html.erb
56
-
57
- ```erb
58
- <head></head>
59
- <body>
60
- <a href="#" data-controller="example" data-action="click->example#increment">
61
- Increment <%= @count.to_i %>
62
- </a>
63
- </body>
64
- </html>
65
- ```
66
-
67
- ### app/javascript/controllers/example.js
68
-
69
- ```javascript
70
- import { Controller } from "stimulus"
71
- import StimulusReflex from "stimulus_reflex"
72
-
73
- export default class extends Controller {
74
- connect() {
75
- StimulusReflex.register(this);
76
- }
77
-
78
- increment() {
79
- // trigger a server-side reflex and a client-side page update
80
- this.stimulate('ExampleReflex#increment', 1);
81
- }
82
- }
83
- ```
84
-
85
- ### app/reflexes/example_reflex.rb
86
-
87
- ```ruby
88
- class ExampleReflex < StimulusReflex::Reflex
89
- def increment(step = 1)
90
- @count = @count.to_i + step
91
- end
92
- end
93
- ```
94
-
95
- The following happens after the `StimulusReflex::Reflex` method call finishes.
96
-
97
- 1. The page that triggered the reflex is re-rerendered. _Instance variables created in the reflex are available to both the controller and view templates._
98
- 2. The re-rendered HTML is sent to the client over the ActionCable socket.
99
- 3. The page is updated via fast DOM diffing courtesy of morphdom. _While future versions of StimulusReflex might support more granular updates, today the entire body is re-rendered and sent over the socket._
100
-
101
- ## Advanced Usage
102
-
103
- ### ActionCable
104
-
105
- StimulusReflex will use the ActionCable defaults of `window.App` and `App.cable` if they exist.
106
- If these defaults do not exist, StimulusReflex will establish a new socket connection.
107
-
108
- ### Performance
109
-
110
- ActionCable emits verbose log messages. Disabling ActionCable logs may improve performance.
111
-
112
- ```ruby
113
- # config/application.rb
114
-
115
- ActionCable.server.config.logger = Logger.new(nil)
116
- ```
117
-
118
- ### ActionCable Rooms
119
-
120
- You may find the need to restrict notifications to a specific room.
121
- This can be accomplished by setting the `data-room` attribute on the StimulusController element.
122
-
123
- ```erb
124
- <a href="#" data-controller="example" data-action="click->example#increment" data-room="12345">
125
- ```
126
-
127
- ### Render Delay
128
-
129
- An attempt is made to reduce repaint/reflow jitter when users trigger lots of updates.
130
-
131
- You can control how long to wait _(think debounce)_ prior to updating the page.
132
- Simply set the `renderDelay` _(milliseconds)_ option when registering the controller.
133
-
134
- ```javascript
135
- export default class extends Controller {
136
- connect() {
137
- StimulusReflex.register(this, {renderDelay: 200});
138
- }
139
- }
140
- ```
141
-
142
- The default value is `25`.
143
-
144
- ## Demo Applications
145
-
146
- Building apps with StimulusReflex should evoke your memories of the original [Rails demo video](https://www.youtube.com/watch?v=Gzj723LkRJY).
147
-
148
- > Look at all the things I'm **not** doing. -DHH
149
-
150
- - [TodoMVC](https://github.com/hopsoft/stimulus_reflex_todomvc)
151
-
152
- <<<<<<< HEAD
153
- ## Contributing
154
-
155
- This project uses [Standard](https://github.com/testdouble/standard)
156
- and [Prettier](https://github.com/prettier/prettier) to minimize bike shedding related to code formatting.
157
- Please run `./bin/standardize` prior submitting pull requests.
158
- =======
159
- >>>>>>> master