stimulus_reflex 1.1.1 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce2617cefcb188998c2f9aca1a440bd2501839a699166cdfa32fba44741af5f5
4
- data.tar.gz: a486389eef17cfa47e8fefef2256cd72a2aff25c1d6ce5713cc49d444565f787
3
+ metadata.gz: 8072c82ab1f16ce62c41e6d970952c3762a9e2fe5d87d2036ff2f37af7f3a4fb
4
+ data.tar.gz: b3549d33023d9c27e878443f48391e13b82562e4dc9d9cbfb64b9744d8fe0702
5
5
  SHA512:
6
- metadata.gz: 36f7b68e56c6446b5125d984378f24207bec848fdfeb99365b99dcac3f9b725e20a99fbd093740e22abc8c8d6fae4b16bd9c470d475289adcd25bb4b177a5563
7
- data.tar.gz: ed8f1e225df23c5b949f2c1f6a4f743521f7b6118f621808b19f46d6716fe812b7c6d475149972ad655737806c3612768d9001cc1f6619b41e2732543a6f6fb4
6
+ metadata.gz: 5ba2646379f9bbe65485d947c55467640e890d516ad571f704e064f0fb78956b977ba405d5698efdb6fd3b7e87f1075a9948d59c4b6ec2855410d3b290137a31
7
+ data.tar.gz: 756a22a1a4cb5f1d4ad985dd1424ed15edc3d2e4d8efcf080d3c3a9a551a170fc1a76d84543fd105acc104b97c07d7f377348a00ec329222fa6341c0e627051c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stimulus_reflex (1.1.1)
4
+ stimulus_reflex (2.0.0)
5
5
  cable_ready (>= 4.0.3)
6
6
  nokogiri
7
7
  rack
data/README.md CHANGED
@@ -1,5 +1,7 @@
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-218-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](https://github.com/hopsoft/stimulus_reflex/workflows/Prettier%20Check%20Action/badge.svg)
4
+ ![StandardRB](https://github.com/hopsoft/stimulus_reflex/workflows/StandardRB%20Check%20Action/badge.svg)
3
5
 
4
6
  # StimulusReflex
5
7
 
@@ -25,14 +27,19 @@ _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
25
27
  - [How it Works](#how-it-works)
26
28
  - [Setup](#setup)
27
29
  * [JavaScript](#javascript)
30
+ + [app/javascript/controllers/index.js](#appjavascriptcontrollersindexjs)
28
31
  * [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)
32
+ - [Usage](#usage)
33
+ * [Implicit Declarative Reflexes](#implicit-declarative-reflexes)
34
+ + [app/views/pages/example.html.erb](#appviewspagesexamplehtmlerb)
35
+ + [app/reflexes/example_reflex.rb](#appreflexesexample_reflexrb)
36
+ * [Explicitly Defined Reflexes](#explicitly-defined-reflexes)
37
+ + [app/views/pages/example.html.erb](#appviewspagesexamplehtmlerb-1)
38
+ + [app/javascript/controllers/example.js](#appjavascriptcontrollersexamplejs)
39
+ + [app/reflexes/example_reflex.rb](#appreflexesexample_reflexrb-1)
40
+ - [What Just Happened](#what-just-happened)
33
41
  - [Advanced Usage](#advanced-usage)
34
- * [Reflex Methods](#reflex-methods)
35
- + [The `options` Keyword Argument](#the-options-keyword-argument)
42
+ * [The Reflex `element` property](#the-reflex-element-property)
36
43
  * [ActionCable](#actioncable)
37
44
  + [Performance](#performance)
38
45
  + [ActionCable Rooms](#actioncable-rooms)
@@ -77,6 +84,21 @@ There are no hidden gotchas.
77
84
  ```
78
85
  yarn add stimulus_reflex
79
86
  ```
87
+ #### app/javascript/controllers/index.js
88
+
89
+ This is the file where Stimulus is initialized in your application.
90
+ _Note that your file location may be different._
91
+
92
+ ```javascript
93
+ import { Application } from 'stimulus';
94
+ import { definitionsFromContext } from 'stimulus/webpack-helpers';
95
+ import StimulusReflex from 'stimulus_reflex';
96
+
97
+ const application = Application.start();
98
+ const context = require.context('controllers', true, /_controller\.js$/);
99
+ application.load(definitionsFromContext(context));
100
+ StimulusReflex.initialize(application);
101
+ ```
80
102
 
81
103
  ### Gemfile
82
104
 
@@ -84,9 +106,47 @@ yarn add stimulus_reflex
84
106
  gem "stimulus_reflex"
85
107
  ```
86
108
 
87
- ## Basic Usage
109
+ ## Usage
110
+
111
+ ### Implicit Declarative Reflexes
112
+
113
+ This example shows how to create a reactive feature without the need to write any JavaScript
114
+ other than initializing StimulusReflex itself _([see the setup instructions](#javascript))_. Everything else is managed entirely by HTML and Ruby.
88
115
 
89
- ### app/views/pages/example.html.erb
116
+ #### app/views/pages/example.html.erb
117
+
118
+ ```erb
119
+ <head></head>
120
+ <body>
121
+ <a href="#" data-reflex="click->ExampleReflex#increment" data-step="1" data-count="<%= @count.to_i %>">
122
+ Increment <%= @count.to_i %>
123
+ </a>
124
+ </body>
125
+ </html>
126
+ ```
127
+
128
+ #### app/reflexes/example_reflex.rb
129
+
130
+ ```ruby
131
+ class ExampleReflex < StimulusReflex::Reflex
132
+ def increment
133
+ @count = element.dataset[:count].to_i + element.dataset[:step].to_i
134
+ end
135
+ end
136
+ ```
137
+
138
+ The code above will automatically update the relevant DOM nodes with the updated count whenever the anchor is clicked.
139
+
140
+ __Note that all concerns from managing state to rendering views are handled server side.__
141
+ This technique works regardless of how complex the UI may become.
142
+ For example, we could render multiple instances of `@count` in unrelated sections of the page and they will all update.
143
+
144
+ ### Explicitly Defined Reflexes
145
+
146
+ This example shows how to create a reactive feature by defining an explicit client side
147
+ Stimulus controller to handle the DOM event and trigger the server side reflex.
148
+
149
+ #### app/views/pages/example.html.erb
90
150
 
91
151
  ```erb
92
152
  <head></head>
@@ -98,7 +158,7 @@ gem "stimulus_reflex"
98
158
  </html>
99
159
  ```
100
160
 
101
- ### app/javascript/controllers/example.js
161
+ #### app/javascript/controllers/example.js
102
162
 
103
163
  ```javascript
104
164
  import { Controller } from "stimulus"
@@ -116,7 +176,7 @@ export default class extends Controller {
116
176
  }
117
177
  ```
118
178
 
119
- ### app/reflexes/example_reflex.rb
179
+ #### app/reflexes/example_reflex.rb
120
180
 
121
181
  ```ruby
122
182
  class ExampleReflex < StimulusReflex::Reflex
@@ -126,65 +186,57 @@ class ExampleReflex < StimulusReflex::Reflex
126
186
  end
127
187
  ```
128
188
 
129
- The following happens after the `StimulusReflex::Reflex` method call finishes.
189
+ ## What Just Happened
190
+
191
+ The following happens when a `StimulusReflex::Reflex` is invoked.
130
192
 
131
193
  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
194
  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
195
+ 3. The page is updated via fast DOM diffing courtesy of morphdom.
138
196
 
139
- #### The `options` Keyword Argument
197
+ _NOTE: While future versions of StimulusReflex may support more granular updates, today the entire body is re-rendered and sent over the socket._
140
198
 
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
199
+ ## Advanced Usage
151
200
 
152
- def other_work(value, options: {})
153
- # ...
154
- end
155
- end
156
- ```
201
+ ### The Reflex `element` property
157
202
 
158
- The `options` value contains all of the Stimulus controller's
203
+ All reflex methods expose an `element` property.
204
+ This property holds a Hash like data structure that represents the HTML element that triggered the refelx.
205
+ It contains all of the Stimulus controller's
159
206
  [DOM element attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) as well as other properties like `checked` and `value`.
160
207
  _Most of the values will be strings._
161
- Here's an example:
162
208
 
163
209
  ```html
164
- <checkbox checked label="Example" data-controller="checkbox" data-value="123" />
210
+ <checkbox id="example"
211
+ label="Example"
212
+ data-controller="checkbox"
213
+ data-value="123"
214
+ checked />
165
215
  ```
166
216
 
167
- The markup above produces the following behavior in a reflex method.
168
-
169
217
  ```ruby
170
218
  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"
219
+ def work()
220
+ element[:id] # => the HTML element's id attribute value
221
+ element.dataset # => a Hash that represents the HTML element's dataset
222
+
223
+ element[:id] # => "example"
224
+ element[:checked] # => true
225
+ element[:label] # => "Example"
226
+ element["data-controller"] # => "checkbox"
227
+ element["data-value"] # => "123"
228
+ element.dataset[:controller] # => "checkbox"
229
+ element.dataset[:value] # => "123"
178
230
  end
179
231
  end
180
232
  ```
181
233
 
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
234
+ - `element[:checked]` holds a boolean
235
+ - `element[:selected]` holds a boolean
236
+ - `element[:value]` holds the [DOM element's value](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#value)
237
+ - `select` elements assign `element[:value]` to their selected option's value
238
+ - `select` elements with _multiselect_ enabled assign `element[:values]` to their selected options values
239
+ - All other values exposed in `element` are extracted from the DOM element's attributes
188
240
 
189
241
  ### ActionCable
190
242
 
@@ -249,11 +301,5 @@ Please run `./bin/standardize` prior submitting pull requests.
249
301
  1. Run `rake build`
250
302
  1. Run `rake release`
251
303
  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
256
-
257
- ```
258
- git push --tags
259
- ```
304
+ 1. Run `yarn publish --tag GIT_TAG_CREATED_BY_RUBYGEMS`
305
+ 1. Assign same version number to the JavaScript package _Might not be required?_
@@ -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
@@ -22,11 +22,11 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
22
22
  reflex_name, method_name = target.split("#")
23
23
  reflex_name = reflex_name.classify
24
24
  arguments = data["args"] || []
25
- options = StimulusReflex::DomElement.new(data["attrs"])
25
+ element = StimulusReflex::Element.new(data["attrs"])
26
26
 
27
27
  begin
28
- reflex = reflex_name.constantize.new(self, url: url)
29
- delegate_call_to_reflex reflex, method_name, arguments, options
28
+ reflex = reflex_name.constantize.new(self, url: url, element: element)
29
+ delegate_call_to_reflex reflex, method_name, arguments
30
30
  rescue => invoke_error
31
31
  logger.error "\e[31mStimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}\e[0m"
32
32
  end
@@ -40,24 +40,15 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
40
40
 
41
41
  private
42
42
 
43
- def delegate_call_to_reflex(reflex, method_name, arguments = [], options = {})
43
+ def delegate_call_to_reflex(reflex, method_name, arguments = [])
44
44
  method = reflex.method(method_name)
45
45
  required_params = method.parameters.select { |(kind, _)| kind == :req }
46
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
47
 
49
48
  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
49
+ reflex.public_send method_name
55
50
  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
51
+ reflex.public_send method_name, *arguments
61
52
  else
62
53
  raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{required_params.inspect}, optional #{optional_params.inspect})")
63
54
  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,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class StimulusReflex::Reflex
4
- attr_reader :channel, :url
4
+ attr_reader :channel, :url, :element
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)
10
10
  @channel = channel
11
11
  @url = url
12
+ @element = element
12
13
  end
13
14
 
14
15
  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.0.0"
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.0.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-09-09 00:00:00.000000000 Z
12
+ date: 2019-09-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -156,7 +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
+ - lib/stimulus_reflex/element.rb
160
160
  - lib/stimulus_reflex/reflex.rb
161
161
  - lib/stimulus_reflex/version.rb
162
162
  homepage: https://github.com/hopsoft/stimulus_reflex