stimulus_reflex 3.5.0.pre1 → 3.5.0.pre2

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.

data/README.md CHANGED
@@ -109,10 +109,10 @@ View the [wiki](https://github.com/stimulusreflex/stimulus_reflex/wiki/Editor-Co
109
109
  ## 📦 Releasing
110
110
 
111
111
  1. Bump version number at `lib/stimulus_reflex/version.rb`
112
- 1. Run `rake build`
113
- 1. Run `rake release`
114
- 1. Run `yarn publish --no-git-tag-version`
115
- 1. Commit and push changes to the `package.json` file
112
+ 2. Run `rake build`
113
+ 3. Run `rake release`
114
+ 4. Run `yarn publish --no-git-tag-version`
115
+ 5. Commit and push changes to the `package.json` file
116
116
 
117
117
  ## 📝 License
118
118
 
@@ -4,11 +4,7 @@ class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.cons
4
4
  attr_reader :reflex_data
5
5
 
6
6
  def stream_name
7
- ids = connection.identifiers.map { |identifier| send(identifier).try(:id) || send(identifier) }
8
- [
9
- params[:channel],
10
- ids.select(&:present?).join(";")
11
- ].select(&:present?).join(":")
7
+ [params[:channel], connection.connection_identifier].join(":")
12
8
  end
13
9
 
14
10
  def subscribed
@@ -92,7 +88,7 @@ class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.cons
92
88
  elsif policy.arguments?
93
89
  reflex.process(method_name, *arguments)
94
90
  else
95
- raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{required_params.inspect}, optional #{optional_params.inspect})")
91
+ raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{policy.required_params.inspect}, optional #{policy.optional_params.inspect})")
96
92
  end
97
93
  end
98
94
 
@@ -1,12 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ApplicationReflex < StimulusReflex::Reflex
4
- # Put application-wide Reflex behavior and callbacks in this file.
4
+ # Put application-wide Reflex behavior and callbacks in this file.
5
5
  #
6
- # Example:
6
+ # Learn more at: https://docs.stimulusreflex.com/rtfm/reflex-classes
7
7
  #
8
- # # If your ActionCable connection is: `identified_by :current_user`
8
+ # If your ActionCable connection is: `identified_by :current_user`
9
9
  # delegate :current_user, to: :connection
10
10
  #
11
- # Learn more at: https://docs.stimulusreflex.com/rtfm/reflex-classes
11
+ # If you need to localize your Reflexes, you can set the I18n locale here:
12
+ #
13
+ # before_reflex do
14
+ # I18n.locale = :fr
15
+ # end
16
+ #
17
+ # For code examples, considerations and caveats, see:
18
+ # https://docs.stimulusreflex.com/rtfm/patterns#internationalization
12
19
  end
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # The ActionCable logger is REALLY noisy, and might even impact performance.
4
+ # Uncomment the line below to silence the ActionCable logger.
5
+
6
+ # ActionCable.server.config.logger = Logger.new(nil)
7
+
3
8
  StimulusReflex.configure do |config|
4
9
  # Enable/disable exiting / warning when the sanity checks fail options:
5
10
  # `:exit` or `:warn` or `:ignore`
@@ -11,6 +16,11 @@ StimulusReflex.configure do |config|
11
16
 
12
17
  # config.on_new_version_available = :ignore
13
18
 
19
+ # Enable/disable exiting / warning when there is no default URLs specified in environment config
20
+ # `:warn` or `:ignore`
21
+
22
+ # config.on_missing_default_urls = :warn
23
+
14
24
  # Override the parent class that the StimulusReflex ActionCable channel inherits from
15
25
 
16
26
  # config.parent_channel = "ApplicationCable::Channel"
@@ -24,6 +24,7 @@ require "stimulus_reflex/broadcasters/broadcaster"
24
24
  require "stimulus_reflex/broadcasters/nothing_broadcaster"
25
25
  require "stimulus_reflex/broadcasters/page_broadcaster"
26
26
  require "stimulus_reflex/broadcasters/selector_broadcaster"
27
+ require "stimulus_reflex/broadcasters/update"
27
28
  require "stimulus_reflex/policies/reflex_invocation_policy"
28
29
  require "stimulus_reflex/utils/colorize"
29
30
  require "stimulus_reflex/utils/logger"
@@ -2,23 +2,17 @@
2
2
 
3
3
  module StimulusReflex
4
4
  class SelectorBroadcaster < Broadcaster
5
- include CableReady::Identifiable
6
-
7
5
  def broadcast(_, data = {})
8
6
  morphs.each do |morph|
9
7
  selectors, html = morph
10
- updates = selectors.is_a?(Hash) ? selectors : {selectors => html}
11
- updates.each do |key, value|
12
- html = reflex.render(key) if key.is_a?(ActiveRecord::Base) && value.nil?
13
- html = reflex.render_collection(key) if key.is_a?(ActiveRecord::Relation) && value.nil?
14
- html ||= value
15
- fragment = Nokogiri::HTML.fragment(html.to_s)
16
- selector = key.is_a?(ActiveRecord::Base) || key.is_a?(ActiveRecord::Relation) ? dom_id(key) : key.to_s
17
- match = fragment.at_css(selector)
8
+ updates = create_update_collection(selectors, html)
9
+ updates.each do |update|
10
+ fragment = Nokogiri::HTML.fragment(update.html.to_s)
11
+ match = fragment.at_css(update.selector)
18
12
  if match.present?
19
- operations << [selector, :morph]
13
+ operations << [update.selector, :morph]
20
14
  cable_ready.morph(
21
- selector: selector,
15
+ selector: update.selector,
22
16
  html: match.inner_html(save_with: Broadcaster::DEFAULT_HTML_WITHOUT_FORMAT),
23
17
  payload: payload,
24
18
  children_only: true,
@@ -28,9 +22,9 @@ module StimulusReflex
28
22
  })
29
23
  )
30
24
  else
31
- operations << [selector, :inner_html]
25
+ operations << [update.selector, :inner_html]
32
26
  cable_ready.inner_html(
33
- selector: selector,
27
+ selector: update.selector,
34
28
  html: fragment.to_html,
35
29
  payload: payload,
36
30
  stimulus_reflex: data.merge({
@@ -64,5 +58,14 @@ module StimulusReflex
64
58
  def to_s
65
59
  "Selector"
66
60
  end
61
+
62
+ private
63
+
64
+ def create_update_collection(selectors, html)
65
+ updates = selectors.is_a?(Hash) ? selectors : {selectors => html}
66
+ updates.map do |key, value|
67
+ StimulusReflex::Broadcasters::Update.new(key, value, reflex)
68
+ end
69
+ end
67
70
  end
68
71
  end
@@ -0,0 +1,23 @@
1
+ module StimulusReflex
2
+ module Broadcasters
3
+ class Update
4
+ include CableReady::Identifiable
5
+
6
+ def initialize(key, value, reflex)
7
+ @key = key
8
+ @value = value
9
+ @reflex = reflex
10
+ end
11
+
12
+ def selector
13
+ @selector ||= identifiable?(@key) ? dom_id(@key) : @key.to_s
14
+ end
15
+
16
+ def html
17
+ html = @reflex.render(@key) if @key.is_a?(ActiveRecord::Base) && @value.nil?
18
+ html = @reflex.render_collection(@key) if @key.is_a?(ActiveRecord::Relation) && @value.nil?
19
+ html || @value
20
+ end
21
+ end
22
+ end
23
+ end
@@ -14,13 +14,14 @@ module StimulusReflex
14
14
  end
15
15
 
16
16
  class Configuration
17
- attr_accessor :on_failed_sanity_checks, :on_new_version_available, :parent_channel, :logging, :middleware
17
+ attr_accessor :on_failed_sanity_checks, :on_new_version_available, :on_missing_default_urls, :parent_channel, :logging, :middleware
18
18
 
19
19
  DEFAULT_LOGGING = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
20
20
 
21
21
  def initialize
22
22
  @on_failed_sanity_checks = :exit
23
23
  @on_new_version_available = :ignore
24
+ @on_missing_default_urls = :warn
24
25
  @parent_channel = "ApplicationCable::Channel"
25
26
  @logging = DEFAULT_LOGGING
26
27
  @middleware = ActionDispatch::MiddlewareStack.new
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class StimulusReflex::Element < OpenStruct
4
- attr_reader :attrs, :data_attrs
4
+ attr_reader :attrs, :data_attrs, :inner_html, :text_content
5
5
 
6
6
  def initialize(data = {})
7
7
  @attrs = HashWithIndifferentAccess.new(data["attrs"] || {})
8
+ @inner_html = data["inner_html"]
9
+ @text_content = data["text_content"]
10
+
8
11
  datasets = data["dataset"] || {}
9
12
  regular_dataset = datasets["dataset"] || {}
10
13
  @data_attrs = build_data_attrs(regular_dataset, datasets["datasetAll"] || {})
11
- all_attributes = @attrs.merge(@data_attrs)
14
+
12
15
  super build_underscored(all_attributes)
16
+
13
17
  @data_attrs.transform_keys! { |key| key.delete_prefix "data-" }
14
18
  end
15
19
 
@@ -29,10 +33,20 @@ class StimulusReflex::Element < OpenStruct
29
33
  @dataset ||= OpenStruct.new(build_underscored(data_attrs))
30
34
  end
31
35
 
36
+ def to_dom_id
37
+ raise NoIDError.new "The element `morph` is called on must have a valid DOM ID" if id.blank?
38
+
39
+ "##{id}"
40
+ end
41
+
32
42
  alias_method :data_attributes, :dataset
33
43
 
34
44
  private
35
45
 
46
+ def all_attributes
47
+ @attrs.merge(@data_attrs)
48
+ end
49
+
36
50
  def build_data_attrs(dataset, dataset_all)
37
51
  dataset_all.transform_keys! { |key| "data-#{key.delete_prefix("data-").pluralize}" }
38
52
 
@@ -46,4 +60,7 @@ class StimulusReflex::Element < OpenStruct
46
60
  def build_underscored(attrs)
47
61
  attrs.merge(attrs.transform_keys(&:underscore))
48
62
  end
63
+
64
+ class NoIDError < StandardError
65
+ end
49
66
  end
@@ -7,14 +7,16 @@ class StimulusReflex::SanityChecker
7
7
 
8
8
  class << self
9
9
  def check!
10
+ return if ENV["SKIP_SANITY_CHECK"]
10
11
  return if StimulusReflex.config.on_failed_sanity_checks == :ignore
11
12
  return if called_by_installer?
12
13
  return if called_by_generate_config?
14
+ return if called_by_rake?
13
15
 
14
16
  instance = new
15
17
  instance.check_caching_enabled
16
- instance.check_javascript_package_version
17
- instance.check_default_url_config
18
+ instance.check_package_versions_match
19
+ # instance.check_default_url_config
18
20
  instance.check_new_version_available
19
21
  end
20
22
 
@@ -29,65 +31,80 @@ class StimulusReflex::SanityChecker
29
31
  def called_by_generate_config?
30
32
  ARGV.include? "stimulus_reflex:initializer"
31
33
  end
34
+
35
+ def called_by_rake?
36
+ File.basename($PROGRAM_NAME) == "rake"
37
+ end
32
38
  end
33
39
 
34
40
  def check_caching_enabled
35
- unless caching_enabled?
41
+ if caching_not_enabled?
36
42
  warn_and_exit <<~WARN
37
- StimulusReflex requires caching to be enabled. Caching allows the session to be modified during ActionCable requests.
43
+ 👉 StimulusReflex requires caching to be enabled. Caching allows the session to be modified during ActionCable requests.
44
+
38
45
  To enable caching in development, run:
46
+
39
47
  rails dev:cache
40
48
  WARN
41
49
  end
42
50
 
43
- unless not_null_store?
51
+ if using_null_store?
44
52
  warn_and_exit <<~WARN
45
- StimulusReflex requires caching to be enabled. Caching allows the session to be modified during ActionCable requests.
46
- But your config.cache_store is set to :null_store, so it won't work.
53
+ 👉 StimulusReflex requires caching to be enabled.
54
+
55
+ Caching allows the session to be modified during ActionCable requests. Your config.cache_store is set to :null_store, so it won't work.
47
56
  WARN
48
57
  end
49
58
  end
50
59
 
51
60
  def check_default_url_config
52
- unless default_url_config_set?
53
- warn_and_exit <<~WARN
54
- StimulusReflex strongly suggests that you set default_url_options in your environment files.
55
- Otherwise, ActionController and ActionMailer will default to example.com when rendering route helpers.
61
+ return if StimulusReflex.config.on_missing_default_urls == :ignore
62
+ if default_url_config_set? == false
63
+ puts <<~WARN
64
+ 👉 StimulusReflex strongly suggests that you set default_url_options in your environment files. Otherwise, ActionController #{"and ActionMailer " if defined?(ActionMailer)}will default to example.com when rendering route helpers.
65
+
56
66
  You can set your URL options in config/environments/#{Rails.env}.rb
67
+
57
68
  config.action_controller.default_url_options = {host: "localhost", port: 3000}
58
- config.action_mailer.default_url_options = {host: "localhost", port: 3000}
69
+ #{"config.action_mailer.default_url_options = {host: \"localhost\", port: 3000}\n" if defined?(ActionMailer)}
59
70
  Please update every environment with the appropriate URL. Typically, no port is necessary in production.
71
+
60
72
  WARN
61
73
  end
62
74
  end
63
75
 
64
- def check_javascript_package_version
65
- if javascript_package_version.nil?
76
+ def check_package_versions_match
77
+ if npm_version.nil?
66
78
  warn_and_exit <<~WARN
67
- Can't locate the stimulus_reflex npm package.
79
+ 👉 Can't locate the stimulus_reflex npm package.
80
+
81
+ yarn add stimulus_reflex@#{gem_version}
82
+
68
83
  Either add it to your package.json as a dependency or use "yarn link stimulus_reflex" if you are doing development.
69
84
  WARN
70
85
  end
71
86
 
72
- unless javascript_version_matches?
87
+ if package_version_mismatch?
73
88
  warn_and_exit <<~WARN
74
- The stimulus_reflex npm package version (#{javascript_package_version}) does not match the Rubygem version (#{gem_version}).
89
+ 👉 The stimulus_reflex npm package version (#{npm_version}) does not match the Rubygem version (#{gem_version}).
90
+
75
91
  To update the stimulus_reflex npm package:
92
+
76
93
  yarn upgrade stimulus_reflex@#{gem_version}
77
94
  WARN
78
95
  end
79
96
  end
80
97
 
81
98
  def check_new_version_available
82
- return unless Rails.env.development?
83
99
  return if StimulusReflex.config.on_new_version_available == :ignore
84
- return unless using_stable_release
100
+ return if Rails.env.development? == false
101
+ return if using_preview_release?
85
102
  begin
86
103
  latest_version = URI.open("https://raw.githubusercontent.com/stimulusreflex/stimulus_reflex/master/LATEST", open_timeout: 1, read_timeout: 1).read.strip
87
104
  if latest_version != StimulusReflex::VERSION
88
105
  puts <<~WARN
89
106
 
90
- There is a new version of StimulusReflex available!
107
+ 👉 There is a new version of StimulusReflex available!
91
108
  Current: #{StimulusReflex::VERSION} Latest: #{latest_version}
92
109
 
93
110
  If you upgrade, it is very important that you update BOTH Gemfile and package.json
@@ -97,43 +114,45 @@ class StimulusReflex::SanityChecker
97
114
  exit if StimulusReflex.config.on_new_version_available == :exit
98
115
  end
99
116
  rescue
100
- puts "StimulusReflex #{StimulusReflex::VERSION} update check skipped: connection timeout"
117
+ puts "👉 StimulusReflex #{StimulusReflex::VERSION} update check skipped: connection timeout"
101
118
  end
102
119
  end
103
120
 
104
- private
105
-
106
- def caching_enabled?
107
- Rails.application.config.action_controller.perform_caching
121
+ def caching_not_enabled?
122
+ Rails.application.config.action_controller.perform_caching == false
108
123
  end
109
124
 
110
- def not_null_store?
111
- Rails.application.config.cache_store != :null_store
125
+ def using_null_store?
126
+ Rails.application.config.cache_store == :null_store
112
127
  end
113
128
 
114
129
  def default_url_config_set?
115
- Rails.application.config.action_controller.default_url_options
130
+ if defined?(ActionMailer)
131
+ Rails.application.config.action_controller.default_url_options.blank? && Rails.application.config.action_mailer.default_url_options.blank?
132
+ else
133
+ Rails.application.config.action_controller.default_url_options.blank?
134
+ end
116
135
  end
117
136
 
118
- def javascript_version_matches?
119
- javascript_package_version == gem_version
137
+ def package_version_mismatch?
138
+ npm_version != gem_version
120
139
  end
121
140
 
122
- def using_stable_release
123
- stable = StimulusReflex::VERSION.match?(LATEST_VERSION_FORMAT)
124
- puts "StimulusReflex #{StimulusReflex::VERSION} update check skipped: pre-release build" unless stable
125
- stable
141
+ def using_preview_release?
142
+ preview = StimulusReflex::VERSION.match?(LATEST_VERSION_FORMAT) == false
143
+ puts "👉 StimulusReflex #{StimulusReflex::VERSION} update check skipped: pre-release build" if preview
144
+ preview
126
145
  end
127
146
 
128
147
  def gem_version
129
148
  @_gem_version ||= StimulusReflex::VERSION.gsub(".pre", "-pre")
130
149
  end
131
150
 
132
- def javascript_package_version
133
- @_js_version ||= find_javascript_package_version
151
+ def npm_version
152
+ @_npm_version ||= find_npm_version
134
153
  end
135
154
 
136
- def find_javascript_package_version
155
+ def find_npm_version
137
156
  if (match = search_file(package_json_path, regex: /version/))
138
157
  match[JSON_VERSION_FORMAT, 1]
139
158
  elsif (match = search_file(yarn_lock_path, regex: /^stimulus_reflex/))
@@ -142,7 +161,7 @@ class StimulusReflex::SanityChecker
142
161
  end
143
162
 
144
163
  def search_file(path, regex:)
145
- return unless File.exist?(path)
164
+ return if File.exist?(path) == false
146
165
  File.foreach(path).grep(regex).first
147
166
  end
148
167
 
@@ -154,49 +173,38 @@ class StimulusReflex::SanityChecker
154
173
  Rails.root.join("yarn.lock")
155
174
  end
156
175
 
157
- def initializer_path
158
- @_initializer_path ||= Rails.root.join("config", "initializers", "stimulus_reflex.rb")
176
+ def initializer_missing?
177
+ File.exist?(Rails.root.join("config", "initializers", "stimulus_reflex.rb")) == false
159
178
  end
160
179
 
161
180
  def warn_and_exit(text)
162
- puts "WARNING:"
181
+ puts
182
+ puts "Heads up! 🔥"
183
+ puts
163
184
  puts text
164
- exit_with_info if StimulusReflex.config.on_failed_sanity_checks == :exit
165
- end
166
-
167
- def exit_with_info
168
185
  puts
169
-
170
- if File.exist?(initializer_path)
171
- puts <<~INFO
172
- If you know what you are doing and you want to start the application anyway,
173
- you can add the following directive to the StimulusReflex initializer,
174
- which is located at #{initializer_path}
175
-
176
- StimulusReflex.configure do |config|
177
- config.on_failed_sanity_checks = :warn
178
- end
179
-
180
- INFO
181
- else
186
+ if StimulusReflex.config.on_failed_sanity_checks == :exit
182
187
  puts <<~INFO
183
- If you know what you are doing and you want to start the application anyway,
184
- you can create a StimulusReflex initializer with the command:
185
-
186
- bundle exec rails generate stimulus_reflex:config
188
+ To ignore any warnings and start the application anyway, you can set the SKIP_SANITY_CHECK environment variable:
187
189
 
188
- Then open your initializer at
190
+ SKIP_SANITY_CHECK=true rails
189
191
 
190
- #{initializer_path}
191
-
192
- and then add the following directive:
192
+ To do this permanently, add the following directive to the StimulusReflex initializer:
193
193
 
194
194
  StimulusReflex.configure do |config|
195
195
  config.on_failed_sanity_checks = :warn
196
196
  end
197
197
 
198
198
  INFO
199
+ if initializer_missing?
200
+ puts <<~INFO
201
+ You can create a StimulusReflex initializer with the command:
202
+
203
+ bundle exec rails generate stimulus_reflex:initializer
204
+
205
+ INFO
206
+ end
207
+ exit false if Rails.env.test? == false
199
208
  end
200
- exit false
201
209
  end
202
210
  end