stimulus_reflex 3.4.0 → 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.

Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +639 -484
  3. data/CODE_OF_CONDUCT.md +6 -0
  4. data/Gemfile.lock +99 -96
  5. data/LATEST +1 -0
  6. data/README.md +15 -14
  7. data/app/channels/stimulus_reflex/channel.rb +42 -73
  8. data/lib/generators/USAGE +1 -1
  9. data/lib/generators/stimulus_reflex/{config_generator.rb → initializer_generator.rb} +3 -3
  10. data/lib/generators/stimulus_reflex/templates/app/reflexes/%file_name%_reflex.rb.tt +3 -2
  11. data/lib/generators/stimulus_reflex/templates/app/reflexes/application_reflex.rb.tt +11 -4
  12. data/lib/generators/stimulus_reflex/templates/config/initializers/stimulus_reflex.rb +16 -1
  13. data/lib/stimulus_reflex.rb +11 -2
  14. data/lib/stimulus_reflex/broadcasters/broadcaster.rb +7 -4
  15. data/lib/stimulus_reflex/broadcasters/page_broadcaster.rb +2 -2
  16. data/lib/stimulus_reflex/broadcasters/selector_broadcaster.rb +20 -10
  17. data/lib/stimulus_reflex/broadcasters/update.rb +23 -0
  18. data/lib/stimulus_reflex/cable_ready_channels.rb +18 -3
  19. data/lib/stimulus_reflex/callbacks.rb +98 -0
  20. data/lib/stimulus_reflex/concern_enhancer.rb +37 -0
  21. data/lib/stimulus_reflex/configuration.rb +3 -1
  22. data/lib/stimulus_reflex/element.rb +48 -7
  23. data/lib/stimulus_reflex/policies/reflex_invocation_policy.rb +28 -0
  24. data/lib/stimulus_reflex/reflex.rb +49 -58
  25. data/lib/stimulus_reflex/reflex_data.rb +79 -0
  26. data/lib/stimulus_reflex/reflex_factory.rb +31 -0
  27. data/lib/stimulus_reflex/request_parameters.rb +19 -0
  28. data/lib/stimulus_reflex/{logger.rb → utils/logger.rb} +6 -8
  29. data/lib/stimulus_reflex/utils/sanity_checker.rb +210 -0
  30. data/lib/stimulus_reflex/version.rb +1 -1
  31. data/lib/tasks/stimulus_reflex/install.rake +54 -15
  32. data/package.json +7 -6
  33. data/stimulus_reflex.gemspec +8 -8
  34. data/test/broadcasters/broadcaster_test_case.rb +1 -1
  35. data/test/broadcasters/nothing_broadcaster_test.rb +5 -3
  36. data/test/broadcasters/page_broadcaster_test.rb +8 -4
  37. data/test/broadcasters/selector_broadcaster_test.rb +171 -55
  38. data/test/callbacks_test.rb +652 -0
  39. data/test/concern_enhancer_test.rb +54 -0
  40. data/test/element_test.rb +181 -0
  41. data/test/reflex_test.rb +2 -2
  42. data/test/test_helper.rb +22 -0
  43. data/test/tmp/app/reflexes/application_reflex.rb +10 -3
  44. data/test/tmp/app/reflexes/demo_reflex.rb +4 -2
  45. data/yarn.lock +1280 -1284
  46. metadata +47 -33
  47. data/lib/stimulus_reflex/sanity_checker.rb +0 -154
  48. data/tags +0 -156
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ class StimulusReflex::SanityChecker
4
+ LATEST_VERSION_FORMAT = /^(\d+\.\d+\.\d+)$/
5
+ NODE_VERSION_FORMAT = /(\d+\.\d+\.\d+.*):/
6
+ JSON_VERSION_FORMAT = /(\d+\.\d+\.\d+.*)"/
7
+
8
+ class << self
9
+ def check!
10
+ return if ENV["SKIP_SANITY_CHECK"]
11
+ return if StimulusReflex.config.on_failed_sanity_checks == :ignore
12
+ return if called_by_installer?
13
+ return if called_by_generate_config?
14
+ return if called_by_rake?
15
+
16
+ instance = new
17
+ instance.check_caching_enabled
18
+ instance.check_package_versions_match
19
+ # instance.check_default_url_config
20
+ instance.check_new_version_available
21
+ end
22
+
23
+ private
24
+
25
+ def called_by_installer?
26
+ Rake.application.top_level_tasks.include? "stimulus_reflex:install"
27
+ rescue
28
+ false
29
+ end
30
+
31
+ def called_by_generate_config?
32
+ ARGV.include? "stimulus_reflex:initializer"
33
+ end
34
+
35
+ def called_by_rake?
36
+ File.basename($PROGRAM_NAME) == "rake"
37
+ end
38
+ end
39
+
40
+ def check_caching_enabled
41
+ if caching_not_enabled?
42
+ warn_and_exit <<~WARN
43
+ 👉 StimulusReflex requires caching to be enabled. Caching allows the session to be modified during ActionCable requests.
44
+
45
+ To enable caching in development, run:
46
+
47
+ rails dev:cache
48
+ WARN
49
+ end
50
+
51
+ if using_null_store?
52
+ warn_and_exit <<~WARN
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.
56
+ WARN
57
+ end
58
+ end
59
+
60
+ def check_default_url_config
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
+
66
+ You can set your URL options in config/environments/#{Rails.env}.rb
67
+
68
+ config.action_controller.default_url_options = {host: "localhost", port: 3000}
69
+ #{"config.action_mailer.default_url_options = {host: \"localhost\", port: 3000}\n" if defined?(ActionMailer)}
70
+ Please update every environment with the appropriate URL. Typically, no port is necessary in production.
71
+
72
+ WARN
73
+ end
74
+ end
75
+
76
+ def check_package_versions_match
77
+ if npm_version.nil?
78
+ warn_and_exit <<~WARN
79
+ 👉 Can't locate the stimulus_reflex npm package.
80
+
81
+ yarn add stimulus_reflex@#{gem_version}
82
+
83
+ Either add it to your package.json as a dependency or use "yarn link stimulus_reflex" if you are doing development.
84
+ WARN
85
+ end
86
+
87
+ if package_version_mismatch?
88
+ warn_and_exit <<~WARN
89
+ 👉 The stimulus_reflex npm package version (#{npm_version}) does not match the Rubygem version (#{gem_version}).
90
+
91
+ To update the stimulus_reflex npm package:
92
+
93
+ yarn upgrade stimulus_reflex@#{gem_version}
94
+ WARN
95
+ end
96
+ end
97
+
98
+ def check_new_version_available
99
+ return if StimulusReflex.config.on_new_version_available == :ignore
100
+ return if Rails.env.development? == false
101
+ return if using_preview_release?
102
+ begin
103
+ latest_version = URI.open("https://raw.githubusercontent.com/stimulusreflex/stimulus_reflex/master/LATEST", open_timeout: 1, read_timeout: 1).read.strip
104
+ if latest_version != StimulusReflex::VERSION
105
+ puts <<~WARN
106
+
107
+ 👉 There is a new version of StimulusReflex available!
108
+ Current: #{StimulusReflex::VERSION} Latest: #{latest_version}
109
+
110
+ If you upgrade, it is very important that you update BOTH Gemfile and package.json
111
+ Then, run `bundle install && yarn install` to update to #{latest_version}.
112
+
113
+ WARN
114
+ exit if StimulusReflex.config.on_new_version_available == :exit
115
+ end
116
+ rescue
117
+ puts "👉 StimulusReflex #{StimulusReflex::VERSION} update check skipped: connection timeout"
118
+ end
119
+ end
120
+
121
+ def caching_not_enabled?
122
+ Rails.application.config.action_controller.perform_caching == false
123
+ end
124
+
125
+ def using_null_store?
126
+ Rails.application.config.cache_store == :null_store
127
+ end
128
+
129
+ def default_url_config_set?
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
135
+ end
136
+
137
+ def package_version_mismatch?
138
+ npm_version != gem_version
139
+ end
140
+
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
145
+ end
146
+
147
+ def gem_version
148
+ @_gem_version ||= StimulusReflex::VERSION.gsub(".pre", "-pre")
149
+ end
150
+
151
+ def npm_version
152
+ @_npm_version ||= find_npm_version
153
+ end
154
+
155
+ def find_npm_version
156
+ if (match = search_file(package_json_path, regex: /version/))
157
+ match[JSON_VERSION_FORMAT, 1]
158
+ elsif (match = search_file(yarn_lock_path, regex: /^stimulus_reflex/))
159
+ match[NODE_VERSION_FORMAT, 1]
160
+ end
161
+ end
162
+
163
+ def search_file(path, regex:)
164
+ return if File.exist?(path) == false
165
+ File.foreach(path).grep(regex).first
166
+ end
167
+
168
+ def package_json_path
169
+ Rails.root.join("node_modules", "stimulus_reflex", "package.json")
170
+ end
171
+
172
+ def yarn_lock_path
173
+ Rails.root.join("yarn.lock")
174
+ end
175
+
176
+ def initializer_missing?
177
+ File.exist?(Rails.root.join("config", "initializers", "stimulus_reflex.rb")) == false
178
+ end
179
+
180
+ def warn_and_exit(text)
181
+ puts
182
+ puts "Heads up! 🔥"
183
+ puts
184
+ puts text
185
+ puts
186
+ if StimulusReflex.config.on_failed_sanity_checks == :exit
187
+ puts <<~INFO
188
+ To ignore any warnings and start the application anyway, you can set the SKIP_SANITY_CHECK environment variable:
189
+
190
+ SKIP_SANITY_CHECK=true rails
191
+
192
+ To do this permanently, add the following directive to the StimulusReflex initializer:
193
+
194
+ StimulusReflex.configure do |config|
195
+ config.on_failed_sanity_checks = :warn
196
+ end
197
+
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
208
+ end
209
+ end
210
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "3.4.0"
4
+ VERSION = "3.5.0.pre2"
5
5
  end
@@ -4,7 +4,7 @@ require "fileutils"
4
4
  require "stimulus_reflex/version"
5
5
 
6
6
  namespace :stimulus_reflex do
7
- desc "Install StimulusReflex in this application"
7
+ desc "Install StimulusReflex in this application"
8
8
  task install: :environment do
9
9
  system "rails dev:cache" unless Rails.root.join("tmp", "caching-dev.txt").exist?
10
10
  gem_version = StimulusReflex::VERSION.gsub(".pre", "-pre")
@@ -25,8 +25,8 @@ namespace :stimulus_reflex do
25
25
  .map { |path| Rails.root.join(path) }
26
26
  .first
27
27
 
28
- puts "Updating #{filepath}"
29
- lines = File.open(filepath, "r") { |f| f.readlines }
28
+ puts "Updating #{filepath}"
29
+ lines = File.readlines(filepath)
30
30
 
31
31
  unless lines.find { |line| line.start_with?("import StimulusReflex") }
32
32
  matches = lines.select { |line| line =~ /\A(require|import)/ }
@@ -44,34 +44,73 @@ namespace :stimulus_reflex do
44
44
  end
45
45
 
46
46
  initialize_line = lines.find { |line| line.start_with?("StimulusReflex.initialize") }
47
- lines << "StimulusReflex.initialize(application, { consumer, controller, isolate: true })\n" unless initialize_line
47
+ lines << "application.consumer = consumer\n"
48
+ lines << "StimulusReflex.initialize(application, { controller, isolate: true })\n" unless initialize_line
48
49
  lines << "StimulusReflex.debug = process.env.RAILS_ENV === 'development'\n" unless initialize_line
49
- File.open(filepath, "w") { |f| f.write lines.join }
50
+ File.write(filepath, lines.join)
50
51
 
52
+ puts
53
+ puts "✨ Updating config/environments/development.rb"
51
54
  filepath = Rails.root.join("config/environments/development.rb")
52
- lines = File.open(filepath, "r") { |f| f.readlines }
55
+ lines = File.readlines(filepath)
53
56
  unless lines.find { |line| line.include?("config.session_store") }
54
- lines.insert 3, " config.session_store :cache_store\n\n"
55
- File.open(filepath, "w") { |f| f.write lines.join }
57
+ matches = lines.select { |line| line =~ /\A(Rails.application.configure do)/ }
58
+ lines.insert lines.index(matches.last).to_i + 1, " config.session_store :cache_store\n\n"
59
+ puts
60
+ puts "✨ Using :cache_store for session storage. We recommend switching to Redis for cache and session storage."
61
+ puts
62
+ puts "https://docs.stimulusreflex.com/appendices/deployment#use-redis-as-your-cache-store"
63
+ File.write(filepath, lines.join)
64
+ end
65
+
66
+ if defined?(ActionMailer)
67
+ lines = File.readlines(filepath)
68
+ unless lines.find { |line| line.include?("config.action_mailer.default_url_options") }
69
+ matches = lines.select { |line| line =~ /\A(Rails.application.configure do)/ }
70
+ lines.insert lines.index(matches.last).to_i + 1, " config.action_mailer.default_url_options = {host: \"localhost\", port: 3000}\n\n"
71
+ File.write(filepath, lines.join)
72
+ end
56
73
  end
57
74
 
75
+ lines = File.readlines(filepath)
76
+ unless lines.find { |line| line.include?("config.action_controller.default_url_options") }
77
+ matches = lines.select { |line| line =~ /\A(Rails.application.configure do)/ }
78
+ lines.insert lines.index(matches.last).to_i + 1, " config.action_controller.default_url_options = {host: \"localhost\", port: 3000}\n"
79
+ File.write(filepath, lines.join)
80
+ end
81
+
82
+ puts
83
+ puts "✨ Updating config/cable.yml to use Redis in development"
58
84
  filepath = Rails.root.join("config/cable.yml")
59
- lines = File.open(filepath, "r") { |f| f.readlines }
85
+ lines = File.readlines(filepath)
60
86
  if lines[1].include?("adapter: async")
61
87
  lines.delete_at 1
62
88
  lines.insert 1, " adapter: redis\n"
63
89
  lines.insert 2, " url: <%= ENV.fetch(\"REDIS_URL\") { \"redis://localhost:6379/1\" } %>\n"
64
- lines.insert 3, " channel_prefix: " + File.basename(Rails.root.to_s).underscore + "_development\n"
65
- File.open(filepath, "w") { |f| f.write lines.join }
90
+ lines.insert 3, " channel_prefix: " + File.basename(Rails.root.to_s).tr("\\", "").tr("-. ", "_").underscore + "_development\n"
91
+ File.write(filepath, lines.join)
66
92
  end
67
93
 
94
+ puts
95
+ puts "✨ Generating default StimulusReflex and CableReady configuration files"
96
+ puts
97
+ system "bundle exec rails generate stimulus_reflex:initializer"
98
+ system "bundle exec rails generate cable_ready:initializer"
99
+ system "bundle exec rails generate cable_ready:stream_from"
100
+
101
+ puts
102
+ puts "✨ Generating ApplicationReflex class and Stimulus controllers, plus an example Reflex class and controller"
103
+ puts
68
104
  system "bundle exec rails generate stimulus_reflex example"
69
- puts "Generating default StimulusReflex configuration file into your application config/initializers directory"
70
- system "bundle exec rails generate stimulus_reflex:config"
71
105
 
72
106
  puts
73
- puts "StimulusReflex and CableReady have been successfully installed!"
74
- puts "Go to https://docs.stimulusreflex.com/quickstart if you need help getting started."
107
+ puts "🎉 StimulusReflex and CableReady have been successfully installed! 🎉"
108
+ puts
109
+ puts "https://docs.stimulusreflex.com/hello-world/quickstart"
110
+ puts
111
+ puts "😊 The fastest way to get support is to say hello on Discord:"
112
+ puts
113
+ puts "https://discord.gg/stimulus-reflex"
75
114
  puts
76
115
  end
77
116
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stimulus_reflex",
3
- "version": "3.4.0-pre9",
3
+ "version": "3.5.0-pre1",
4
4
  "description": "Build reactive applications with the Rails tooling you already know and love.",
5
5
  "keywords": [
6
6
  "ruby",
@@ -20,28 +20,28 @@
20
20
  ],
21
21
  "homepage": "https://docs.stimulusreflex.com/",
22
22
  "bugs": {
23
- "url": "https://github.com/hopsoft/stimulus_reflex/issues"
23
+ "url": "https://github.com/stimulusreflex/stimulus_reflex/issues"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
27
- "url": "git+https://github.com:hopsoft/stimulus_reflex.git"
27
+ "url": "git+https://github.com:stimulusreflex/stimulus_reflex.git"
28
28
  },
29
29
  "license": "MIT",
30
30
  "author": "Nathan Hopkins <natehop@gmail.com>",
31
+ "sideEffects": false,
31
32
  "main": "./javascript/stimulus_reflex.js",
32
33
  "module": "./javascript/stimulus_reflex.js",
33
34
  "scripts": {
34
- "postinstall": "node ./javascript/scripts/post_install.js",
35
35
  "prettier-standard:check": "yarn run prettier-standard --check ./javascript/*.js ./javascript/**/*.js",
36
36
  "prettier-standard:format": "yarn run prettier-standard ./javascript/*.js ./javascript/**/*.js",
37
- "test": "yarn run mocha --require @babel/register --require esm ./javascript/test"
37
+ "test": "yarn run mocha --require @babel/register --require jsdom-global/register --require esm ./javascript/test"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "stimulus": ">= 1.1"
41
41
  },
42
42
  "dependencies": {
43
43
  "@rails/actioncable": ">= 6.0",
44
- "cable_ready": ">= 4.4"
44
+ "cable_ready": "5.0.0-pre2"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@babel/core": "^7.6.2",
@@ -50,6 +50,7 @@
50
50
  "assert": "^2.0.0",
51
51
  "esm": "^3.2.25",
52
52
  "jsdom": "^16.0.1",
53
+ "jsdom-global": "^3.0.2",
53
54
  "mocha": "^8.0.1",
54
55
  "prettier-standard": "^16.1.0",
55
56
  "stimulus": ">= 1.1"
@@ -8,18 +8,18 @@ Gem::Specification.new do |gem|
8
8
  gem.version = StimulusReflex::VERSION
9
9
  gem.authors = ["Nathan Hopkins"]
10
10
  gem.email = ["natehop@gmail.com"]
11
- gem.homepage = "https://github.com/hopsoft/stimulus_reflex"
11
+ gem.homepage = "https://github.com/stimulusreflex/stimulus_reflex"
12
12
  gem.summary = "Build reactive applications with the Rails tooling you already know and love."
13
13
  gem.post_install_message = <<~MESSAGE
14
- Friendly reminder: When updating the stimulus_reflex gem,
15
- don't forget to update your npm package as well.
14
+ Get support for StimulusReflex and CableReady on Discord:
15
+
16
+ https://discord.gg/stimulus-reflex
16
17
 
17
- See https://www.npmjs.com/package/stimulus_reflex
18
18
  MESSAGE
19
19
 
20
20
  gem.metadata = {
21
- "bug_tracker_uri" => "https://github.com/hopsoft/stimulus_reflex/issues",
22
- "changelog_uri" => "https://github.com/hopsoft/stimulus_reflex/CHANGELOG.md",
21
+ "bug_tracker_uri" => "https://github.com/stimulusreflex/stimulus_reflex/issues",
22
+ "changelog_uri" => "https://github.com/stimulusreflex/stimulus_reflex/CHANGELOG.md",
23
23
  "documentation_uri" => "https://docs.stimulusreflex.com",
24
24
  "homepage_uri" => gem.homepage,
25
25
  "source_code_uri" => gem.homepage
@@ -32,11 +32,11 @@ Gem::Specification.new do |gem|
32
32
  gem.add_dependency "nokogiri"
33
33
  gem.add_dependency "rails", ">= 5.2"
34
34
  gem.add_dependency "redis"
35
- gem.add_dependency "cable_ready", ">= 4.4"
35
+ gem.add_dependency "cable_ready", "5.0.0.pre2"
36
36
 
37
37
  gem.add_development_dependency "bundler", "~> 2.0"
38
38
  gem.add_development_dependency "pry-nav"
39
39
  gem.add_development_dependency "pry"
40
40
  gem.add_development_dependency "rake"
41
- gem.add_development_dependency "standardrb"
41
+ gem.add_development_dependency "standardrb", "~> 1.0"
42
42
  end
@@ -10,6 +10,6 @@ class StimulusReflex::BroadcasterTestCase < ActionCable::Channel::TestCase
10
10
  def connection.env
11
11
  @env ||= {}
12
12
  end
13
- @reflex = StimulusReflex::Reflex.new(subscribe, url: "https://test.stimulusreflex.com")
13
+ @reflex = StimulusReflex::Reflex.new(subscribe, url: "https://test.stimulusreflex.com", client_attributes: {reflex_id: "666"})
14
14
  end
15
15
  end
@@ -13,7 +13,8 @@ class StimulusReflex::NothingBroadcasterTest < StimulusReflex::BroadcasterTestCa
13
13
  {
14
14
  "name" => "stimulus-reflex:server-message",
15
15
  "detail" => {
16
- "reflexId" => nil,
16
+ "reflexId" => "666",
17
+ "payload" => {},
17
18
  "stimulusReflex" => {
18
19
  "some" => :data,
19
20
  "morph" => :nothing,
@@ -22,14 +23,15 @@ class StimulusReflex::NothingBroadcasterTest < StimulusReflex::BroadcasterTestCa
22
23
  "body" => nil
23
24
  }
24
25
  }
25
- }
26
+ },
27
+ "reflexId" => "666"
26
28
  }
27
29
  ]
28
30
  }
29
31
  }
30
32
 
31
33
  assert_broadcast_on @reflex.stream_name, expected do
32
- broadcaster.broadcast nil, some: :data
34
+ broadcaster.broadcast nil, {:some => :data, "reflexId" => "666"}
33
35
  end
34
36
  end
35
37
  end