stimulus_reflex 1.1.1 → 2.1.1

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.
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