stimulus_reflex 3.4.0.pre0 → 3.4.0.pre5

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.

@@ -8,9 +8,10 @@ module StimulusReflex
8
8
 
9
9
  return unless page_html.present?
10
10
 
11
- document = Nokogiri::HTML(page_html)
11
+ document = Nokogiri::HTML.parse(page_html)
12
12
  selectors = selectors.select { |s| document.css(s).present? }
13
13
  selectors.each do |selector|
14
+ operations << [selector, :morph]
14
15
  html = document.css(selector).inner_html
15
16
  cable_ready[stream_name].morph(
16
17
  selector: selector,
@@ -32,5 +33,9 @@ module StimulusReflex
32
33
  def page?
33
34
  true
34
35
  end
36
+
37
+ def to_s
38
+ "Page"
39
+ end
35
40
  end
36
41
  end
@@ -11,6 +11,7 @@ module StimulusReflex
11
11
  fragment = Nokogiri::HTML.fragment(html)
12
12
  match = fragment.at_css(selector)
13
13
  if match.present?
14
+ operations << [selector, :morph]
14
15
  cable_ready[stream_name].morph(
15
16
  selector: selector,
16
17
  html: match.inner_html,
@@ -21,6 +22,7 @@ module StimulusReflex
21
22
  })
22
23
  )
23
24
  else
25
+ operations << [selector, :inner_html]
24
26
  cable_ready[stream_name].inner_html(
25
27
  selector: selector,
26
28
  html: fragment.to_html,
@@ -40,6 +42,10 @@ module StimulusReflex
40
42
  @morphs ||= []
41
43
  end
42
44
 
45
+ def append_morph(selectors, html)
46
+ morphs << [selectors, html]
47
+ end
48
+
43
49
  def to_sym
44
50
  :selector
45
51
  end
@@ -47,5 +53,9 @@ module StimulusReflex
47
53
  def selector?
48
54
  true
49
55
  end
56
+
57
+ def to_s
58
+ "Selector"
59
+ end
50
60
  end
51
61
  end
@@ -14,11 +14,14 @@ module StimulusReflex
14
14
  end
15
15
 
16
16
  class Configuration
17
- attr_accessor :exit_on_failed_sanity_checks, :parent_channel
17
+ attr_accessor :on_failed_sanity_checks, :parent_channel, :logging
18
+
19
+ DEFAULT_LOGGING = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
18
20
 
19
21
  def initialize
20
- @exit_on_failed_sanity_checks = true
22
+ @on_failed_sanity_checks = :exit
21
23
  @parent_channel = "ApplicationCable::Channel"
24
+ @logging = DEFAULT_LOGGING
22
25
  end
23
26
  end
24
27
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusReflex
4
+ class Logger
5
+ attr_accessor :reflex, :current_operation
6
+
7
+ def initialize(reflex)
8
+ @reflex = reflex
9
+ @current_operation = 1
10
+ end
11
+
12
+ def print
13
+ return unless config_logging.instance_of?(Proc)
14
+
15
+ puts
16
+ reflex.broadcaster.operations.each do
17
+ puts instance_eval(&config_logging) + "\e[0m"
18
+ @current_operation += 1
19
+ end
20
+ puts
21
+ end
22
+
23
+ private
24
+
25
+ def config_logging
26
+ return @config_logging if @config_logging
27
+
28
+ StimulusReflex.config.logging.binding.eval("using StimulusReflex::Utils::Colorize")
29
+ @config_logging = StimulusReflex.config.logging
30
+ end
31
+
32
+ def session_id_full
33
+ session = reflex.request&.session
34
+ session.nil? ? "-" : session.id
35
+ end
36
+
37
+ def session_id
38
+ session_id_full.to_s[0..7]
39
+ end
40
+
41
+ def reflex_info
42
+ reflex.class.to_s + "#" + reflex.method_name
43
+ end
44
+
45
+ def reflex_id_full
46
+ reflex.reflex_id
47
+ end
48
+
49
+ def reflex_id
50
+ reflex_id_full[0..7]
51
+ end
52
+
53
+ def mode
54
+ reflex.broadcaster.to_s
55
+ end
56
+
57
+ def selector
58
+ reflex.broadcaster.operations[current_operation - 1][0]
59
+ end
60
+
61
+ def operation
62
+ reflex.broadcaster.operations[current_operation - 1][1].to_s
63
+ end
64
+
65
+ def operation_counter
66
+ current_operation.to_s + "/" + reflex.broadcaster.operations.size.to_s
67
+ end
68
+
69
+ def connection_id_full
70
+ identifier = reflex.connection&.connection_identifier
71
+ identifier.empty? ? "-" : identifier
72
+ end
73
+
74
+ def connection_id
75
+ connection_id_full[0..7]
76
+ end
77
+
78
+ def timestamp
79
+ Time.now.strftime("%Y-%m-%d %H:%M:%S")
80
+ end
81
+
82
+ def method_missing method
83
+ return send(method.to_sym) if private_instance_methods.include?(method.to_sym)
84
+
85
+ reflex.connection.identifiers.each do |identifier|
86
+ ident = reflex.connection.send(identifier)
87
+ return ident.send(method) if ident.respond_to?(:attributes) && ident.attributes.key?(method.to_s)
88
+ end
89
+ "-"
90
+ end
91
+
92
+ def respond_to_missing? method
93
+ return true if private_instance_methods.include?(method.to_sym)
94
+
95
+ reflex.connection.identifiers.each do |identifier|
96
+ ident = reflex.connection.send(identifier)
97
+ return true if ident.respond_to?(:attributes) && ident.attributes.key?(method.to_s)
98
+ end
99
+ false
100
+ end
101
+
102
+ def private_instance_methods
103
+ StimulusReflex::Logger.private_instance_methods(false)
104
+ end
105
+ end
106
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ClientAttributes = Struct.new(:reflex_id, :reflex_controller, :xpath, :c_xpath, :permanent_attribute_name, keyword_init: true)
4
+
3
5
  class StimulusReflex::Reflex
4
6
  include ActiveSupport::Rescuable
5
7
  include ActiveSupport::Callbacks
@@ -43,23 +45,25 @@ class StimulusReflex::Reflex
43
45
  end
44
46
  end
45
47
 
46
- attr_reader :channel, :url, :element, :selectors, :method_name, :broadcaster, :permanent_attribute_name
48
+ attr_reader :channel, :url, :element, :selectors, :method_name, :broadcaster, :client_attributes, :logger
47
49
 
48
50
  alias_method :action_name, :method_name # for compatibility with controller libraries like Pundit that expect an action name
49
51
 
50
52
  delegate :connection, :stream_name, to: :channel
51
53
  delegate :flash, :session, to: :request
52
54
  delegate :broadcast, :broadcast_message, to: :broadcaster
55
+ delegate :reflex_id, :reflex_controller, :xpath, :c_xpath, :permanent_attribute_name, to: :client_attributes
53
56
 
54
- def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, permanent_attribute_name: nil, params: {})
57
+ def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, params: {}, client_attributes: {})
55
58
  @channel = channel
56
59
  @url = url
57
60
  @element = element
58
61
  @selectors = selectors
59
62
  @method_name = method_name
60
63
  @params = params
61
- @permanent_attribute_name = permanent_attribute_name
62
64
  @broadcaster = StimulusReflex::PageBroadcaster.new(self)
65
+ @logger = StimulusReflex::Logger.new(self)
66
+ @client_attributes = ClientAttributes.new(client_attributes)
63
67
  self.params
64
68
  end
65
69
 
@@ -104,7 +108,7 @@ class StimulusReflex::Reflex
104
108
  else
105
109
  raise StandardError.new("Cannot call :selector morph after :nothing morph") if broadcaster.nothing?
106
110
  @broadcaster = StimulusReflex::SelectorBroadcaster.new(self) unless broadcaster.selector?
107
- broadcaster.morphs << [selectors, html]
111
+ broadcaster.append_morph(selectors, html)
108
112
  end
109
113
  end
110
114
 
@@ -3,10 +3,21 @@
3
3
  class StimulusReflex::SanityChecker
4
4
  JSON_VERSION_FORMAT = /(\d+\.\d+\.\d+.*)"/
5
5
 
6
- def self.check!
7
- instance = new
8
- instance.check_caching_enabled
9
- instance.check_javascript_package_version
6
+ class << self
7
+ def check!
8
+ return if StimulusReflex.config.on_failed_sanity_checks == :ignore
9
+ return if called_by_generate_config?
10
+
11
+ instance = new
12
+ instance.check_caching_enabled
13
+ instance.check_javascript_package_version
14
+ end
15
+
16
+ private
17
+
18
+ def called_by_generate_config?
19
+ ARGV.include? "stimulus_reflex:config"
20
+ end
10
21
  end
11
22
 
12
23
  def check_caching_enabled
@@ -80,19 +91,50 @@ class StimulusReflex::SanityChecker
80
91
  Rails.root.join("node_modules", "stimulus_reflex", "package.json")
81
92
  end
82
93
 
94
+ def initializer_path
95
+ @_initializer_path ||= Rails.root.join("config", "initializers", "stimulus_reflex.rb")
96
+ end
97
+
83
98
  def warn_and_exit(text)
84
99
  puts "WARNING:"
85
100
  puts text
86
- exit_with_info if StimulusReflex.config.exit_on_failed_sanity_checks
101
+ exit_with_info if StimulusReflex.config.on_failed_sanity_checks == :exit
87
102
  end
88
103
 
89
104
  def exit_with_info
90
105
  puts
91
- puts <<~INFO
92
- If you know what you are doing and you want to start the application anyway,
93
- you can add the following directive to an initializer:
94
- StimulusReflex.config.exit_on_failed_sanity_checks = false
95
- INFO
96
- exit
106
+
107
+ # bundle exec rails generate stimulus_reflex:config
108
+ if File.exist?(initializer_path)
109
+ puts <<~INFO
110
+ If you know what you are doing and you want to start the application anyway,
111
+ you can add the following directive to the StimulusReflex initializer,
112
+ which is located at #{initializer_path}
113
+
114
+ StimulusReflex.configure do |config|
115
+ config.on_failed_sanity_checks = :warn
116
+ end
117
+
118
+ INFO
119
+ else
120
+ puts <<~INFO
121
+ If you know what you are doing and you want to start the application anyway,
122
+ you can create a StimulusReflex initializer with the command:
123
+
124
+ bundle exec rails generate stimulus_reflex:config
125
+
126
+ Then open your initializer at
127
+
128
+ <RAILS_ROOT>/config/initializers/stimulus_reflex.rb
129
+
130
+ and then add the following directive:
131
+
132
+ StimulusReflex.configure do |config|
133
+ config.on_failed_sanity_checks = :warn
134
+ end
135
+
136
+ INFO
137
+ end
138
+ exit false
97
139
  end
98
140
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusReflex
4
+ module Utils
5
+ module Colorize
6
+ COLORS = {
7
+ red: "31",
8
+ green: "32",
9
+ yellow: "33",
10
+ blue: "34",
11
+ magenta: "35",
12
+ cyan: "36",
13
+ white: "37"
14
+ }
15
+
16
+ refine String do
17
+ COLORS.each do |name, code|
18
+ define_method(name) { "\e[#{code}m#{self}\e[0m" }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "3.4.0.pre0"
4
+ VERSION = "3.4.0.pre5"
5
5
  end
@@ -8,7 +8,7 @@ namespace :stimulus_reflex do
8
8
  task install: :environment do
9
9
  system "bundle exec rails webpacker:install:stimulus"
10
10
  gem_version = StimulusReflex::VERSION.gsub(".pre", "-pre")
11
- system "yarn add cable_ready stimulus_reflex@#{gem_version}"
11
+ system "yarn add stimulus_reflex@#{gem_version}"
12
12
  main_folder = defined?(Webpacker) ? Webpacker.config.source_path.to_s.gsub("#{Rails.root}/", "") : "app/javascript"
13
13
 
14
14
  FileUtils.mkdir_p Rails.root.join("#{main_folder}/controllers"), verbose: true
@@ -60,11 +60,12 @@ namespace :stimulus_reflex do
60
60
  lines.delete_at 1
61
61
  lines.insert 1, " adapter: redis\n"
62
62
  lines.insert 2, " url: <%= ENV.fetch(\"REDIS_URL\") { \"redis://localhost:6379/1\" } %>\n"
63
- lines.insert 3, " channel_prefix: " + Rails.application.class.module_parent.to_s.underscore + "_development\n"
63
+ lines.insert 3, " channel_prefix: " + File.basename(Rails.root.to_s).underscore + "_development\n"
64
64
  File.open(filepath, "w") { |f| f.write lines.join }
65
65
  end
66
66
 
67
67
  system "bundle exec rails generate stimulus_reflex example"
68
+ puts "Generating default StimulusReflex configuration file into your application config/initializers directory"
68
69
  system "bundle exec rails generate stimulus_reflex:config"
69
70
  system "rails dev:cache" unless Rails.root.join("tmp", "caching-dev.txt").exist?
70
71
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stimulus_reflex",
3
- "version": "3.3.0",
3
+ "version": "3.4.0-pre4",
4
4
  "description": "Build reactive applications with the Rails tooling you already know and love.",
5
5
  "keywords": [
6
6
  "ruby",
@@ -28,34 +28,28 @@
28
28
  },
29
29
  "license": "MIT",
30
30
  "author": "Nathan Hopkins <natehop@gmail.com>",
31
- "source": "javascript/stimulus_reflex.js",
32
- "main": "javascript/dist/stimulus_reflex.js",
33
- "module": "javascript/dist/stimulus_reflex.module.js",
34
- "esmodule": "javascript/dist/stimulus_reflex.modern.js",
31
+ "main": "./javascript/stimulus_reflex.js",
32
+ "module": "./javascript/stimulus_reflex.js",
35
33
  "scripts": {
36
- "prepare": "yarn build",
37
- "postinstall": "node javascript/scripts/post_install.js",
38
- "prettier-standard:check": "yarn run prettier-standard --check *.js **/*.js",
39
- "prettier-standard:format": "yarn run prettier-standard *.js **/*.js",
40
- "test": "yarn run mocha --require @babel/register --require esm ./javascript/test",
41
- "build": "microbundle --target browser --format modern,es,cjs --no-strict",
42
- "dev": "microbundle watch --target browser --format modern,es,cjs --no-strict"
34
+ "postinstall": "node ./javascript/scripts/post_install.js",
35
+ "prettier-standard:check": "yarn run prettier-standard --check ./javascript/*.js ./javascript/**/*.js",
36
+ "prettier-standard:format": "yarn run prettier-standard ./javascript/*.js ./javascript/**/*.js",
37
+ "test": "yarn run mocha --require @babel/register --require esm ./javascript/test"
43
38
  },
44
39
  "peerDependencies": {
45
- "@rails/actioncable": ">= 6.0",
46
- "cable_ready": ">= 4.3.0",
47
40
  "stimulus": ">= 1.1"
48
41
  },
42
+ "dependencies": {
43
+ "@rails/actioncable": ">= 6.0",
44
+ "cable_ready": ">= 4.3.0"
45
+ },
49
46
  "devDependencies": {
50
47
  "@babel/core": "^7.6.2",
51
48
  "@babel/preset-env": "^7.6.2",
52
49
  "@babel/register": "^7.6.2",
53
- "@rails/actioncable": "^6.0.3-3",
54
50
  "assert": "^2.0.0",
55
- "cable_ready": "^4.4.0-pre2",
56
51
  "esm": "^3.2.25",
57
52
  "jsdom": "^16.0.1",
58
- "microbundle": "^0.12.3",
59
53
  "mocha": "^8.0.1",
60
54
  "prettier-standard": "^16.1.0",
61
55
  "stimulus": "^1.1.1"
@@ -23,14 +23,14 @@ Gem::Specification.new do |gem|
23
23
  "source_code_uri" => gem.homepage
24
24
  }
25
25
 
26
- gem.files = Dir["lib/**/*", "bin/*", "[A-Z]*"]
26
+ gem.files = Dir["app/**/*", "lib/**/*", "bin/*", "[A-Z]*"]
27
27
  gem.test_files = Dir["test/**/*.rb"]
28
28
 
29
29
  gem.add_dependency "rack"
30
30
  gem.add_dependency "nokogiri"
31
31
  gem.add_dependency "rails", ">= 5.2"
32
- gem.add_dependency "cable_ready", ">= 4.3.0"
33
32
  gem.add_dependency "redis"
33
+ gem.add_dependency "cable_ready", ">= 4.3.0"
34
34
 
35
35
  gem.add_development_dependency "bundler", "~> 2.0"
36
36
  gem.add_development_dependency "pry-nav"
@@ -0,0 +1,15 @@
1
+ require_relative "../test_helper"
2
+
3
+ class StimulusReflex::BroadcasterTest < ActiveSupport::TestCase
4
+ setup do
5
+ @reflex = Minitest::Mock.new
6
+ @reflex.expect :stream_name, "TestStream"
7
+ end
8
+
9
+ test "raises a NotImplementedError if called directly" do
10
+ broadcaster = StimulusReflex::Broadcaster.new(@reflex)
11
+
12
+ assert_raises(NotImplementedError) { broadcaster.broadcast }
13
+ assert_raises(NotImplementedError) { broadcaster.broadcast_message(subject: "Test") }
14
+ end
15
+ end