rux-rails 1.4.0 → 1.5.0

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.
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe "html safety" do
4
+ it "escapes HTML" do
5
+ render_inline(HtmlSafetyComponent.new(value: "<p>Foo</p>"))
6
+ expect(rendered_content).to eq(
7
+ "<div>&lt;p&gt;Foo&lt;/p&gt;</div>"
8
+ )
9
+ end
10
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,8 @@
1
- require 'pry-byebug'
2
-
3
1
  ENV['RAILS_ENV'] ||= 'test'
4
2
 
5
3
  require 'rails'
6
- require 'rux-rails'
7
-
8
4
  require 'action_controller/railtie'
5
+ require 'rux-rails'
9
6
 
10
7
  Dir.chdir(File.join(*%w(spec dummy))) do
11
8
  require File.expand_path(File.join(*%w(dummy config application)), __dir__)
@@ -14,13 +11,65 @@ end
14
11
 
15
12
  require 'rspec/rails'
16
13
 
17
- module SpecHelpers
18
- extend RSpec::SharedContext
14
+ module RuxRails
15
+ module SpecHelpers
16
+ extend RSpec::SharedContext
17
+ include Capybara::RSpecMatchers
18
+
19
+ let(:app) { Rails.application }
20
+
21
+ before(:each) do
22
+ Dir.glob("spec/dummy/app/components/*.rb").each do |f|
23
+ File.unlink(f)
24
+ end
25
+ end
26
+
27
+ def with_file_contents(path, contents)
28
+ old_contents = ::File.read(path)
29
+ ::File.write(path, contents)
30
+ yield
31
+ ensure
32
+ ::File.write(path, old_contents)
33
+ end
34
+
35
+ attr_reader :rendered_content
36
+
37
+ def page
38
+ @page ||= Capybara::Node::Simple.new(rendered_content)
39
+ end
40
+
41
+ def render_inline(component, **args, &block)
42
+ @page = nil
43
+ @rendered_content =
44
+ if Rails.version.to_f >= 6.1
45
+ vc_test_controller.view_context.render(component, args, &block)
46
+ else
47
+ vc_test_controller.view_context.render_component(component, &block)
48
+ end
49
+
50
+ Nokogiri::HTML.fragment(@rendered_content)
51
+ end
52
+
53
+ def vc_test_controller
54
+ @vc_test_controller ||= __vc_test_helpers_build_controller(ViewComponent::Base.test_controller.constantize)
55
+ end
56
+
57
+ def __vc_test_helpers_build_controller(klass)
58
+ klass.new.tap { |c| c.request = vc_test_request }.extend(Rails.application.routes.url_helpers)
59
+ end
19
60
 
20
- let(:app) { Rails.application }
61
+ def vc_test_request
62
+ @vc_test_request ||=
63
+ begin
64
+ out = ActionDispatch::TestRequest.create
65
+ out.session = ActionController::TestSession.new
66
+ out
67
+ end
68
+ end
69
+ end
21
70
  end
22
71
 
23
72
  RSpec.configure do |config|
24
- config.include(SpecHelpers)
73
+ config.include(RuxRails::SpecHelpers)
25
74
  config.include(Capybara::RSpecMatchers, type: :request)
26
75
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rux-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-08 00:00:00.000000000 Z
11
+ date: 2023-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rux
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: railties
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '4'
61
+ - !ruby/object:Gem::Dependency
62
+ name: onload
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
61
75
  description: Rux view components on Rails.
62
76
  email:
63
77
  - camertron@gmail.com
@@ -75,13 +89,9 @@ files:
75
89
  - lib/rux-rails/components/audio.rb
76
90
  - lib/rux-rails/components/image.rb
77
91
  - lib/rux-rails/components/video.rb
78
- - lib/rux-rails/core_ext/kernel.rb
79
- - lib/rux-rails/core_ext/kernel_zeitwerk.rb
80
- - lib/rux-rails/ext/activesupport/dependencies.rb
81
- - lib/rux-rails/ext/bootsnap/autoload.rb
82
- - lib/rux-rails/ext/zeitwerk/loader.rb
92
+ - lib/rux-rails/output_buffer.rb
83
93
  - lib/rux-rails/railtie.rb
84
- - lib/rux-rails/safe_buffer.rb
94
+ - lib/rux-rails/rux_loader.rb
85
95
  - lib/rux-rails/tag_builder.rb
86
96
  - lib/rux-rails/tasks/transpile.rake
87
97
  - lib/rux-rails/template_handler.rb
@@ -91,10 +101,10 @@ files:
91
101
  - spec/controllers/home_controller_spec.rb
92
102
  - spec/dummy/app/assets/config/manifest.js
93
103
  - spec/dummy/app/assets/images/cat.png
94
- - spec/dummy/app/components/button.rb
95
104
  - spec/dummy/app/components/button.rux
96
- - spec/dummy/app/components/home_component.rb
97
105
  - spec/dummy/app/components/home_component.rux
106
+ - spec/dummy/app/components/html_safety_component.rb
107
+ - spec/dummy/app/components/html_safety_component.rux
98
108
  - spec/dummy/app/controllers/application_controller.rb
99
109
  - spec/dummy/app/controllers/home_controller.rb
100
110
  - spec/dummy/app/views/home/index.html.ruxt
@@ -103,11 +113,12 @@ files:
103
113
  - spec/dummy/config/routes.rb
104
114
  - spec/dummy/config/secrets.yml
105
115
  - spec/dummy/log/test.log
116
+ - spec/html_safety_spec.rb
106
117
  - spec/spec_helper.rb
107
118
  homepage: http://github.com/camertron/rux-rails
108
119
  licenses: []
109
120
  metadata: {}
110
- post_install_message:
121
+ post_install_message:
111
122
  rdoc_options: []
112
123
  require_paths:
113
124
  - lib
@@ -122,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
133
  - !ruby/object:Gem::Version
123
134
  version: '0'
124
135
  requirements: []
125
- rubygems_version: 3.1.6
126
- signing_key:
136
+ rubygems_version: 3.4.1
137
+ signing_key:
127
138
  specification_version: 4
128
139
  summary: Rux view components on Rails.
129
140
  test_files: []
@@ -1,67 +0,0 @@
1
- module RuxRails
2
- module LoadPatch
3
- def load(file, *args)
4
- # ActiveSupport::Dependencies adds an extra .rb to the end
5
- if file.end_with?('.rux.rb')
6
- file = file.chomp('.rb')
7
- end
8
-
9
- if file.end_with?('.rux')
10
- tmpl = Rux::File.new(file)
11
- tmpl.write if RuxRails.transpile_on_load?
12
-
13
- return super(tmpl.default_outfile, *args)
14
- end
15
-
16
- super(file, *args)
17
- end
18
- end
19
-
20
- module RequirePatch
21
- def require(file)
22
- # check to see if there's a .rux file somewhere on the load path
23
- path = nil
24
- rux_file = file.end_with?('.rux') ? file : "#{file}.rux"
25
-
26
- if File.absolute_path(rux_file) == rux_file && File.exist?(rux_file)
27
- path = rux_file
28
- elsif rux_file.start_with?(".#{File::SEPARATOR}")
29
- abs_path = File.expand_path(rux_file)
30
- path = abs_path if File.exist?(abs_path)
31
- else
32
- $LOAD_PATH.each do |lp|
33
- check_path = File.expand_path(File.join(lp, rux_file))
34
-
35
- if File.exist?(check_path)
36
- path = check_path
37
- break
38
- end
39
- end
40
- end
41
-
42
- return super(file) unless path
43
- return false if $LOADED_FEATURES.include?(path)
44
-
45
- # Must call the Kernel.load class method here because that's the one
46
- # activesupport doesn't mess with, and in fact the one activesupport
47
- # itself uses to actually load files. In case you were curious,
48
- # activesupport redefines Object#load and Object#require i.e. the
49
- # instance versions that get inherited by all other objects. Yeah,
50
- # it's pretty awful stuff.
51
- Kernel.load(path)
52
- $LOADED_FEATURES << path
53
-
54
- return true
55
- end
56
- end
57
- end
58
-
59
- module Kernel
60
- class << self
61
- prepend RuxRails::LoadPatch
62
- end
63
- end
64
-
65
- class Object
66
- prepend RuxRails::RequirePatch
67
- end
@@ -1,63 +0,0 @@
1
- require 'zeitwerk'
2
-
3
- module Kernel
4
- alias_method :rux_orig_require, :require
5
- alias_method :rux_orig_load, :load
6
-
7
- def load(file, *args)
8
- if File.extname(file) == '.rux'
9
- tmpl = Rux::File.new(file)
10
- tmpl.write if RuxRails.transpile_on_load?
11
-
12
- # I don't understand why, but it's necessary to delete the constant
13
- # in order to load the .ruxc file. Otherwise you get an error about
14
- # an uninitialized constant, and it's like... yeah, I _know_ it's
15
- # uninitialized, that's why I'm loading this file. Whatevs.
16
- loader = Zeitwerk::Registry.loader_for(file)
17
- parent, cname = loader.send(:autoloads)[file]
18
- parent.send(:remove_const, cname)
19
-
20
- return rux_orig_load(tmpl.default_outfile, *args)
21
- end
22
-
23
- rux_orig_load(file, *args)
24
- end
25
-
26
- def require(file)
27
- path = nil
28
- loader = Zeitwerk::Registry.loader_for(file)
29
- rux_file = file.end_with?('.rux') ? file : "#{file}.rux"
30
-
31
- if File.absolute_path(rux_file) == rux_file && File.exist?(rux_file)
32
- path = rux_file
33
- elsif rux_file.start_with?(".#{File::SEPARATOR}")
34
- abs_path = File.expand_path(rux_file)
35
- path = abs_path if File.exist?(abs_path)
36
- else
37
- $LOAD_PATH.each do |lp|
38
- check_path = File.expand_path(File.join(lp, rux_file))
39
-
40
- if File.exist?(check_path)
41
- path = check_path
42
- break
43
- end
44
- end
45
- end
46
-
47
- unless path
48
- # This will be either Ruby's original require or bootsnap's monkeypatched
49
- # require in setups that use bootsnap. Lord help us with all these layers
50
- # of patches.
51
- return rux_orig_require(file)
52
- end
53
-
54
- return false if $LOADED_FEATURES.include?(path)
55
-
56
- load path
57
- $LOADED_FEATURES << path
58
-
59
- loader.on_file_autoloaded(path) if loader
60
-
61
- return true
62
- end
63
- end
@@ -1,47 +0,0 @@
1
- require 'active_support/dependencies'
2
-
3
- module RuxRails
4
- module ActiveSupportDependenciesPatch
5
- # Allow activesupport to find .rux files.
6
- def search_for_file(path_suffix)
7
- path_suffix_with_ext = path_suffix.sub(/(\.rux)?$/, '.rux'.freeze)
8
-
9
- autoload_paths.each do |root|
10
- path = File.join(root, path_suffix_with_ext)
11
- return path if File.file?(path)
12
- end
13
-
14
- super
15
- end
16
-
17
- # For some reason, using autoload and a patched Kernel#load doesn't work
18
- # by itself for automatically loading .rux files. Due to what I can only
19
- # surmise is one of the side-effects of autoload, requiring any .rux file
20
- # that's been marked by autoload will result in a NameError, i.e. Ruby
21
- # reports the constant isn't defined. Pretty surprising considering we're
22
- # literally in the process of _defining_ that constant. The trick is to
23
- # essentially undo the autoload by removing the constant just before
24
- # loading the .rux file that defines it.
25
- def load_missing_constant(from_mod, const_name)
26
- if require_path = from_mod.autoload?(const_name)
27
- path = search_for_file(require_path)
28
-
29
- if path && path.end_with?('.rux')
30
- from_mod.send(:remove_const, const_name)
31
- require require_path
32
- return from_mod.const_get(const_name)
33
- end
34
- end
35
-
36
- super
37
- end
38
- end
39
- end
40
-
41
- module ActiveSupport
42
- module Dependencies
43
- class << self
44
- prepend RuxRails::ActiveSupportDependenciesPatch
45
- end
46
- end
47
- end
@@ -1,27 +0,0 @@
1
- module RuxRails
2
- module BootsnapAutoloadPatch
3
- def autoload(const, path)
4
- # Bootsnap monkeypatches Module.autoload in order to leverage its load
5
- # path cache, which effectively converts a relative path into an absolute
6
- # one without incurring the cost of searching the load path.
7
- # Unfortunately, if a .rux file has already been transpiled, the cache
8
- # seems to always return the corresponding .rb file. Bootsnap's autoload
9
- # patch passes the .rb file to Ruby's original autoload, effectively
10
- # wiping out the previous autoload that pointed to the .rux file. To
11
- # fix this we have to intercept the cache lookup and force autoloading
12
- # the .rux file if one exists.
13
- cached_path = Bootsnap::LoadPathCache.load_path_cache.find(path)
14
- cached_rux_path = "#{cached_path.chomp('.rb')}.rux"
15
-
16
- if File.file?(cached_rux_path)
17
- autoload_without_bootsnap(const, cached_rux_path)
18
- else
19
- super
20
- end
21
- end
22
- end
23
- end
24
-
25
- class Module
26
- prepend RuxRails::BootsnapAutoloadPatch
27
- end
@@ -1,35 +0,0 @@
1
- require 'zeitwerk'
2
-
3
- module RuxRails
4
- module ZeitwerkLoaderPatch
5
- private
6
-
7
- def ruby?(path)
8
- super || path.end_with?('.rux')
9
- end
10
-
11
- def autoload_file(parent, cname, file)
12
- if file.end_with?('.rux')
13
- # Some older versions of Zeitwerk very naïvely try to remove only the
14
- # last 3 characters in an attempt to strip off the .rb file extension,
15
- # while newer ones only remove it if it's actually there. This line is
16
- # necessary to remove the trailing leftover period for older versions,
17
- # and remove the entire .rux extension for newer versions.
18
- cname = cname.to_s.chomp('.').chomp('.rux').to_sym
19
- else
20
- # if there is a corresponding .rux file, autoload it instead of the .rb
21
- # file
22
- rux_file = "#{file.chomp('.rb')}.rux"
23
- file = rux_file if File.exist?(rux_file)
24
- end
25
-
26
- super
27
- end
28
- end
29
- end
30
-
31
- module Zeitwerk
32
- class Loader
33
- prepend RuxRails::ZeitwerkLoaderPatch
34
- end
35
- end
@@ -1,13 +0,0 @@
1
- require 'active_support'
2
-
3
- module RuxRails
4
- class SafeBuffer < ActiveSupport::SafeBuffer
5
- def <<(value)
6
- if value.is_a?(Array)
7
- super(value.map { |v| html_escape_interpolated_argument(v) }.join.html_safe)
8
- else
9
- super
10
- end
11
- end
12
- end
13
- end
@@ -1,15 +0,0 @@
1
- class Button < ViewComponent::Base
2
- attr_reader(:outline, :size, :disabled)
3
-
4
- def initialize(outline:, size:, disabled:)
5
- @outline = outline
6
- @size = size
7
- @disabled = disabled
8
- end
9
-
10
- def call
11
- Rux.tag("button") {
12
- content
13
- }
14
- end
15
- end
@@ -1,12 +0,0 @@
1
- class HomeComponent < ViewComponent::Base
2
- def call
3
- Rux.tag("div", { class: "container" }) {
4
- Rux.create_buffer.tap { |_rux_buf_|
5
- _rux_buf_ << render(Image.new(src: "cat.png", size: "40"))
6
- _rux_buf_ << render(Button.new(outline: true, disabled: "true", size: :large)) {
7
- "Click Me!"
8
- }
9
- }.to_s
10
- }
11
- end
12
- end