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

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