stimulus_reflex 3.5.0.pre1 → 3.5.0.pre2

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.

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