phlex 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of phlex might be problematic. Click here for more details.

Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -1
  3. data/Gemfile +26 -13
  4. data/README.md +1 -1
  5. data/SECURITY.md +1 -1
  6. data/bench.rb +7 -0
  7. data/config/sus.rb +15 -0
  8. data/docs/assets/application.css +6 -0
  9. data/docs/build.rb +2 -0
  10. data/docs/components/callout.rb +1 -1
  11. data/docs/components/code_block.rb +2 -2
  12. data/docs/components/code_span.rb +1 -1
  13. data/docs/components/example.rb +4 -4
  14. data/docs/components/heading.rb +2 -2
  15. data/docs/components/layout.rb +55 -32
  16. data/docs/components/markdown.rb +13 -28
  17. data/docs/components/nav/item.rb +1 -1
  18. data/docs/components/nav.rb +1 -1
  19. data/docs/components/tabs/tab.rb +1 -1
  20. data/docs/components/tabs.rb +1 -1
  21. data/docs/components/title.rb +2 -2
  22. data/docs/pages/application_page.rb +1 -1
  23. data/docs/pages/helpers.rb +5 -5
  24. data/docs/pages/library/collections.rb +4 -22
  25. data/docs/pages/rails/getting_started.rb +1 -1
  26. data/docs/pages/rails/helpers.rb +3 -1
  27. data/docs/pages/rails/layouts.rb +2 -2
  28. data/docs/pages/rails/rendering_views.rb +1 -1
  29. data/docs/pages/templates.rb +6 -6
  30. data/docs/pages/testing/capybara.rb +48 -0
  31. data/docs/pages/testing/getting_started.rb +44 -0
  32. data/docs/pages/testing/nokogiri.rb +83 -0
  33. data/docs/pages/testing/rails.rb +17 -0
  34. data/docs/pages/translations.rb +81 -0
  35. data/docs/pages/views.rb +56 -8
  36. data/fixtures/compiler_test_helpers.rb +19 -0
  37. data/fixtures/content.rb +60 -0
  38. data/fixtures/dummy/app/views/application_view.rb +8 -0
  39. data/fixtures/dummy/app/views/articles/form.rb +1 -1
  40. data/fixtures/dummy/app/views/card.rb +1 -1
  41. data/fixtures/dummy/app/views/comments/comment.rb +1 -1
  42. data/fixtures/dummy/app/views/comments/reaction.rb +1 -1
  43. data/fixtures/dummy/app/views/heading.rb +1 -1
  44. data/fixtures/layout.rb +5 -5
  45. data/fixtures/page.rb +18 -24
  46. data/fixtures/{test_helper.rb → rails_helper.rb} +3 -8
  47. data/fixtures/standard_element.rb +87 -0
  48. data/fixtures/view_helper.rb +1 -1
  49. data/fixtures/void_element.rb +31 -0
  50. data/lib/generators/phlex/collection/templates/collection.rb.erb +2 -1
  51. data/lib/generators/phlex/controller/USAGE +10 -0
  52. data/lib/generators/phlex/controller/controller_generator.rb +54 -0
  53. data/lib/generators/phlex/controller/templates/controller.rb.erb +10 -0
  54. data/lib/generators/phlex/controller/templates/view.rb.erb +14 -0
  55. data/lib/generators/phlex/layout/templates/layout.rb.erb +2 -1
  56. data/lib/generators/phlex/page/templates/page.rb.erb +3 -1
  57. data/lib/generators/phlex/table/templates/table.rb.erb +3 -1
  58. data/lib/generators/phlex/view/templates/view.rb.erb +7 -1
  59. data/lib/generators/phlex/view/view_generator.rb +9 -1
  60. data/lib/install/phlex.rb +10 -1
  61. data/lib/phlex/block.rb +2 -4
  62. data/lib/phlex/buffered.rb +6 -8
  63. data/lib/phlex/callable.rb +9 -0
  64. data/lib/phlex/collection.rb +2 -27
  65. data/lib/phlex/compiler/elements.rb +49 -0
  66. data/lib/phlex/compiler/generators/content.rb +103 -0
  67. data/lib/phlex/compiler/generators/element.rb +61 -0
  68. data/lib/phlex/compiler/nodes/base.rb +19 -0
  69. data/lib/phlex/compiler/nodes/call.rb +9 -0
  70. data/lib/phlex/compiler/nodes/command.rb +13 -0
  71. data/lib/phlex/compiler/nodes/fcall.rb +18 -0
  72. data/lib/phlex/compiler/nodes/method_add_block.rb +33 -0
  73. data/lib/phlex/compiler/nodes/vcall.rb +9 -0
  74. data/lib/phlex/compiler/optimizer.rb +66 -0
  75. data/lib/phlex/compiler/visitors/base.rb +15 -0
  76. data/lib/phlex/compiler/visitors/file.rb +23 -11
  77. data/lib/phlex/compiler/visitors/stable_scope.rb +28 -0
  78. data/lib/phlex/compiler/visitors/statements.rb +36 -0
  79. data/lib/phlex/compiler/visitors/view.rb +19 -0
  80. data/lib/phlex/compiler/visitors/view_method.rb +59 -0
  81. data/lib/phlex/compiler.rb +23 -3
  82. data/lib/phlex/elements.rb +57 -0
  83. data/lib/phlex/helpers.rb +59 -0
  84. data/lib/phlex/html/callbacks.rb +11 -0
  85. data/lib/phlex/html.rb +208 -47
  86. data/lib/phlex/markdown.rb +76 -0
  87. data/lib/phlex/rails/form.rb +67 -0
  88. data/lib/phlex/rails/helpers.rb +39 -2
  89. data/lib/phlex/rails.rb +10 -0
  90. data/lib/phlex/renderable.rb +9 -3
  91. data/lib/phlex/testing/capybara.rb +25 -0
  92. data/lib/phlex/testing/nokogiri.rb +24 -0
  93. data/lib/phlex/testing/rails.rb +19 -0
  94. data/lib/phlex/testing/view_helper.rb +15 -0
  95. data/lib/phlex/translation.rb +23 -0
  96. data/lib/phlex/turbo/frame.rb +21 -0
  97. data/lib/phlex/turbo/stream.rb +18 -0
  98. data/lib/phlex/version.rb +1 -1
  99. data/lib/phlex.rb +22 -24
  100. metadata +62 -14
  101. data/.rspec +0 -1
  102. data/fixtures/compilation/vcall.rb +0 -38
  103. data/lib/phlex/compiler/generators/standard_element.rb +0 -30
  104. data/lib/phlex/compiler/generators/void_element.rb +0 -29
  105. data/lib/phlex/compiler/optimizers/base_optimizer.rb +0 -34
  106. data/lib/phlex/compiler/optimizers/vcall.rb +0 -29
  107. data/lib/phlex/compiler/visitors/base_visitor.rb +0 -19
  108. data/lib/phlex/compiler/visitors/component.rb +0 -28
  109. data/lib/phlex/compiler/visitors/component_method.rb +0 -28
  110. data/lib/phlex/view.rb +0 -229
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5606a60fd7cce19c44c13c26ec1abb42f52252b71208aa77f7cecf49f95910be
4
- data.tar.gz: 0c55bae86c2f14514108f7d58ab9c6e7d3bc88b5a89cc8cbb7156b86e355041d
3
+ metadata.gz: 6db4c22ebfaa77371b1d2bc5faaa48bc93056c3c57e2233fc19a9191850f52f9
4
+ data.tar.gz: b6fc151034426d7ccede55fdd2c73a1244fdf47c440cdb9c59850853cc2cec30
5
5
  SHA512:
6
- metadata.gz: 60e835cad9721dcf6c353d84963a93bb2518b307df493f9a4c2fcaf737a69bdb9b7c32ed5b9e8a5c0049c1fea6445e77d75988de7998d4b65ac4b9781dc038e0
7
- data.tar.gz: 664c9e1fb555019b40085ad49de87bc2f99619d19157603445590a7179390a52ba66dee614896d8c5901abce5fce1f34031a3b1a6e03931bcad76ba41b48e035
6
+ metadata.gz: 888e31c18af9de0230970228e1ab20aab4d08d6b2236187ec06fbe2690813032c3af1e9a675bc737016c3c51f3c522be9a4e87bf868882778ff02482ca4c742f
7
+ data.tar.gz: 6a999b53c9e54a1159ee0ce34e135d3e5f4c3e73a6207f3d5dbec4f208387c165a83e66cc39f26d582d8ff5fe1d32bb7667b3cfae33a3b16d8a69179dcab4131
data/.rubocop.yml CHANGED
@@ -1,6 +1,26 @@
1
1
  inherit_from:
2
- - "https://www.goodcop.style"
2
+ - "https://www.goodcop.style/rubocop.yml"
3
3
  - "https://www.goodcop.style/tabs.yml"
4
4
 
5
5
  AllCops:
6
6
  TargetRubyVersion: 2.7
7
+
8
+ Style/PercentLiteralDelimiters:
9
+ Enabled: false
10
+
11
+ Layout/CaseIndentation:
12
+ Enabled: false
13
+
14
+ Style/StringConcatenation:
15
+ Enabled: false
16
+
17
+
18
+
19
+ Security/Eval:
20
+ Enabled: false
21
+
22
+ Style/MethodCallWithoutArgsParentheses:
23
+ Enabled: false
24
+
25
+ Style/MixinUsage:
26
+ Enabled: false
data/Gemfile CHANGED
@@ -5,19 +5,32 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5
5
 
6
6
  gemspec
7
7
 
8
- gem "rake"
9
-
10
- gem "sus", group: [:test]
11
- gem "rails", group: [:test]
12
- gem "rouge", group: [:docs]
13
- gem "webrick", group: [:docs]
14
- gem "zeitwerk", group: [:docs]
15
- gem "redcarpet", group: [:docs]
16
- gem "combustion", group: [:test]
17
8
  gem "benchmark-ips"
18
- gem "htmlbeautifier", group: [:docs]
19
9
  gem "benchmark-memory"
20
- gem "rubocop", require: false, github: "joeldrapper/rubocop", branch: "rubocop-user-agent"
10
+ gem "capybara"
11
+ gem "rails"
12
+ gem "rubocop"
13
+ gem "solargraph"
14
+ gem "sus"
21
15
  gem "syntax_suggest"
22
- gem "foreman"
23
- gem "filewatcher", group: [:docs]
16
+ gem "zeitwerk"
17
+
18
+ group :test do
19
+ gem "i18n"
20
+ gem "memory_profiler"
21
+ gem "covered"
22
+ end
23
+
24
+ group :rails do
25
+ gem "combustion"
26
+ end
27
+
28
+ group :docs do
29
+ gem "filewatcher"
30
+ gem "htmlbeautifier"
31
+ gem "redcarpet"
32
+ gem "commonmarker", "~> 0.23"
33
+ gem "webrick"
34
+ gem "rouge"
35
+ gem "kramdown"
36
+ end
data/README.md CHANGED
@@ -20,7 +20,7 @@ Maintaining a library is a lot of work. If your company benefits from this work
20
20
 
21
21
  ### Security 🚨
22
22
 
23
- If you’ve found a potential security issue, please email [joel+security@drapper.me](mailto:joel+security@drapper.me).
23
+ If you’ve found a potential security issue, please email [security@phlex.fun](mailto:security@phlex.fun).
24
24
 
25
25
  ### Thanks 🙏
26
26
 
data/SECURITY.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  ## Reporting a Vulnerability
4
4
 
5
- If you found a possible security vulnerability in Phlex, please email joel+security@drapper.me.
5
+ If you found a possible security vulnerability in Phlex, please email security@phlex.fun.
data/bench.rb CHANGED
@@ -9,6 +9,13 @@ require_relative "fixtures/layout"
9
9
 
10
10
  puts RUBY_DESCRIPTION
11
11
 
12
+ a = Example::Page.new.call
13
+ # Example::Page.compile
14
+ # Example::LayoutComponent.compile
15
+ b = Example::Page.new.call
16
+
17
+ raise unless a == b
18
+
12
19
  Benchmark.ips do |x|
13
20
  x.report("Page") { Example::Page.new.call }
14
21
  end
data/config/sus.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "covered/sus"
4
+ include Covered::Sus
5
+
6
+ require "phlex"
7
+ require "bundler"
8
+ require "view_component"
9
+
10
+ Bundler.require :test
11
+
12
+ require_relative "../fixtures/view_helper"
13
+ require_relative "../fixtures/compiler_test_helpers"
14
+
15
+ Zeitwerk::Loader.eager_load_all
@@ -24,3 +24,9 @@ pre { tab-size: 2; }
24
24
  p {
25
25
  @apply my-5
26
26
  }
27
+
28
+ .prose ol, .prose ul {
29
+ list-style: revert;
30
+ margin: 0 0 0 1rem;
31
+ padding: 0 0 0 1rem;
32
+ }
data/docs/build.rb CHANGED
@@ -6,12 +6,14 @@ $stdout.sync = true
6
6
  require "phlex"
7
7
  require "bundler"
8
8
  require "fileutils"
9
+ require "i18n"
9
10
 
10
11
  Bundler.require :docs
11
12
 
12
13
  loader = Zeitwerk::Loader.new
13
14
  loader.push_dir(__dir__)
14
15
  loader.ignore(__FILE__)
16
+ loader.inflector.inflect("rspec" => "RSpec")
15
17
  loader.enable_reloading
16
18
  loader.setup
17
19
  loader.eager_load
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Callout < Phlex::View
4
+ class Callout < Phlex::HTML
5
5
  def template(&block)
6
6
  div(class: "rounded bg-orange-50 text-sm p-5 border border-orange-100", &block)
7
7
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class CodeBlock < Phlex::View
4
+ class CodeBlock < Phlex::HTML
5
5
  FORMATTER = Rouge::Formatters::HTML.new
6
6
 
7
7
  def initialize(code, syntax:)
@@ -11,7 +11,7 @@ module Components
11
11
 
12
12
  def template
13
13
  pre(class: "highlight p-5 whitespace-pre-wrap bg-stone-50") {
14
- raw FORMATTER.format(
14
+ unsafe_raw FORMATTER.format(
15
15
  lexer.lex(@code)
16
16
  )
17
17
  }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class CodeSpan < Phlex::View
4
+ class CodeSpan < Phlex::HTML
5
5
  def template(&block)
6
6
  code(class: "bg-stone-50 inline-block font-medium rounded border px-1 -mt-1", &block)
7
7
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Example < Phlex::View
4
+ class Example < Phlex::HTML
5
5
  def initialize
6
6
  @sandbox = Module.new
7
7
  end
@@ -13,12 +13,12 @@ module Components
13
13
  end
14
14
  end
15
15
 
16
- def tab(name, code)
16
+ def tab(name, code, syntax: :ruby)
17
17
  @t.tab(name) do
18
- render CodeBlock.new(code, syntax: :ruby)
18
+ render CodeBlock.new(code, syntax: syntax)
19
19
  end
20
20
 
21
- @sandbox.class_eval(code)
21
+ @sandbox.class_eval(code) if syntax == :ruby
22
22
  end
23
23
 
24
24
  def execute(code)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Heading < Phlex::View
4
+ class Heading < Phlex::HTML
5
5
  def template(&block)
6
- h2(class: "text-2xl font-semibold mt-10 mb-5") { raw(&block) }
6
+ h2(class: "text-2xl font-semibold mt-10 mb-5", &block)
7
7
  end
8
8
  end
9
9
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Layout < Phlex::View
4
+ class Layout < Phlex::HTML
5
5
  register_element :style
6
6
 
7
7
  def initialize(title:)
@@ -14,53 +14,76 @@ module Components
14
14
  html do
15
15
  head do
16
16
  meta charset: "utf-8"
17
+ meta name: "viewport", content: "width=device-width, initial-scale=1"
17
18
  title { @title }
18
19
  link href: "/application.css", rel: "stylesheet"
19
- style { raw Rouge::Theme.find("github").render(scope: ".highlight") }
20
+ style { unsafe_raw Rouge::Theme.find("github").render(scope: ".highlight") }
20
21
  end
21
22
 
22
23
  body class: "text-stone-700" do
23
- header class: "border-b py-4 px-10 flex justify-between items-center" do
24
- a(href: "/", class: "block") { img src: "/assets/logo.png", width: "100" }
24
+ div class: "flex flex-col" do
25
+ header class: "border-b py-4 px-4 lg:px-10 flex justify-between items-center sticky top-0 left-0 bg-white z-50" do
26
+ div class: "flex flex-row items-center gap-2" do
27
+ label for: "nav-toggle", class: "cursor-pointer lg:hidden" do
28
+ unsafe_raw '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8"> <path fill-rule="evenodd" d="M3 6.75A.75.75 0 013.75 6h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 6.75zM3 12a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 12zm0 5.25a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75a.75.75 0 01-.75-.75z" clip-rule="evenodd" /> </svg>'
29
+ end
25
30
 
26
- nav(class: "text-stone-500 font-medium") do
27
- ul(class: "flex space-x-8") do
28
- li { a(href: "https://github.com/sponsors/joeldrapper") { "💖️ Sponsor" } }
29
- li { a(href: "https://github.com/joeldrapper/phlex") { "GitHub" } }
31
+ a(href: "/", class: "block") { img src: "/assets/logo.png", width: "100" }
32
+ end
33
+
34
+ nav(class: "text-stone-500 font-medium") do
35
+ ul(class: "flex space-x-8") do
36
+ li { a(href: "https://github.com/sponsors/joeldrapper") { "💖️ Sponsor" } }
37
+ li { a(href: "https://github.com/joeldrapper/phlex") { "GitHub" } }
38
+ end
30
39
  end
31
40
  end
32
- end
33
41
 
34
- div class: "grid grid-cols-4 divide-x" do
35
- nav class: "col-span-1 px-10 py-5" do
36
- h2(class: "text-lg font-semibold pt-5") { "Guide" }
42
+ div do
43
+ div class: "flex flex-row" do
44
+ input type: "checkbox", id: "nav-toggle", class: "flex-0 peer hidden"
45
+ label for: "nav-toggle", class: "top-0 bottom-0 left-0 right-0 bg-gray-900 opacity-0 transition-all peer-checked:fixed peer-checked:z-30 peer-checked:block peer-checked:opacity-50 lg:hidden lg:peer-checked:hidden"
46
+ nav class: "fixed lg:relative w-3/4 border-r-2 border-gray-100 lg:border-0 lg:w-1/4 text-lg lg:text-base h-full z-40 px-10 py-5 -left-full transition-all peer-checked:left-0 lg:left-0 bg-white" do
47
+ h2(class: "text-lg font-semibold pt-5") { "Guide" }
37
48
 
38
- ul do
39
- render Nav::Item.new("Introduction", to: Pages::Index, active_page: @_parent)
40
- render Nav::Item.new("Views", to: Pages::Views, active_page: @_parent)
41
- render Nav::Item.new("Templates", to: Pages::Templates, active_page: @_parent)
42
- render Nav::Item.new("Helpers", to: Pages::Helpers, active_page: @_parent)
43
- end
49
+ ul do
50
+ render Nav::Item.new("Introduction", to: Pages::Index, active_page: @_parent)
51
+ render Nav::Item.new("Views", to: Pages::Views, active_page: @_parent)
52
+ render Nav::Item.new("Templates", to: Pages::Templates, active_page: @_parent)
53
+ render Nav::Item.new("Helpers", to: Pages::Helpers, active_page: @_parent)
54
+ render Nav::Item.new("Translations", to: Pages::Translations, active_page: @_parent)
55
+ end
56
+
57
+ h2(class: "text-lg font-semibold pt-5") { "Testing" }
58
+
59
+ ul do
60
+ render Nav::Item.new("Getting Started", to: Pages::Testing::GettingStarted, active_page: @_parent)
61
+ render Nav::Item.new("Nokogiri", to: Pages::Testing::Nokogiri, active_page: @_parent)
62
+ render Nav::Item.new("Capybara", to: Pages::Testing::Capybara, active_page: @_parent)
63
+ render Nav::Item.new("Rails", to: Pages::Testing::Rails, active_page: @_parent)
64
+ end
44
65
 
45
- h2(class: "text-lg font-semibold pt-5") { "Rails" }
66
+ h2(class: "text-lg font-semibold pt-5") { "Rails" }
46
67
 
47
- ul do
48
- render Nav::Item.new("Getting started", to: Pages::Rails::GettingStarted, active_page: @_parent)
49
- render Nav::Item.new("Rendering views", to: Pages::Rails::RenderingViews, active_page: @_parent)
50
- render Nav::Item.new("Laouts", to: Pages::Rails::Layouts, active_page: @_parent)
51
- render Nav::Item.new("Helpers", to: Pages::Rails::Helpers, active_page: @_parent)
52
- render Nav::Item.new("Migrating to Phlex", to: Pages::Rails::Migrating, active_page: @_parent)
68
+ ul do
69
+ render Nav::Item.new("Getting started", to: Pages::Rails::GettingStarted, active_page: @_parent)
70
+ render Nav::Item.new("Rendering views", to: Pages::Rails::RenderingViews, active_page: @_parent)
71
+ render Nav::Item.new("Layouts", to: Pages::Rails::Layouts, active_page: @_parent)
72
+ render Nav::Item.new("Helpers", to: Pages::Rails::Helpers, active_page: @_parent)
73
+ render Nav::Item.new("Migrating to Phlex", to: Pages::Rails::Migrating, active_page: @_parent)
74
+ end
75
+ end
76
+
77
+ main class: "w-full lg:w-3/4 px-6 lg:px-20 py-5 border-0 lg:border-l-2 border-gray-100" do
78
+ div(class: "max-w-full lg:max-w-prose prose", &block)
79
+ end
53
80
  end
54
- end
55
81
 
56
- main class: "col-span-3 px-20 px-10 py-5" do
57
- div(class: "max-w-prose prose", &block)
82
+ footer class: "border-t p-20 flex justify-center text-stone-500 text-lg font-medium" do
83
+ a(href: "https://github.com/sponsors/joeldrapper") { "Sponsor this project 💖" }
84
+ end
58
85
  end
59
86
  end
60
-
61
- footer class: "border-t p-20 flex justify-center text-stone-500 text-lg font-medium" do
62
- a(href: "https://github.com/sponsors/joeldrapper") { "Sponsor this project 💖" }
63
- end
64
87
  end
65
88
  end
66
89
  end
@@ -1,40 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Markdown < Phlex::View
5
- class Render < Redcarpet::Render::HTML
6
- include Redcarpet::Render::SmartyPants
7
-
8
- def header(text, level)
9
- case level
10
- when 1
11
- Title.new.call { CGI.unescapeHTML(text) }
12
- else
13
- Heading.new.call { CGI.unescapeHTML(text) }
14
- end
15
- end
16
-
17
- def codespan(code)
18
- CodeSpan.new.call { code }
19
- end
20
-
21
- def block_code(code, language)
22
- CodeBlock.new(code.gsub(/(?:^|\G) {4}/m, " "), syntax: language).call
23
- end
4
+ class Markdown < Phlex::Markdown
5
+ def code(&content)
6
+ render CodeSpan.new, &content
7
+ end
24
8
 
25
- def html_escape(input)
26
- input
27
- end
9
+ def code_block(code, language:)
10
+ render CodeBlock.new(code.gsub(/(?:^|\G) {4}/m, " "), syntax: language)
28
11
  end
29
12
 
30
- MARKDOWN = Redcarpet::Markdown.new(Render.new, filter_html: false, autolink: true, fenced_code_blocks: true, tables: true, highlight: true, escape_html: false)
13
+ def h1(&content)
14
+ render Title.new, &content
15
+ end
31
16
 
32
- def initialize(content)
33
- @content = content
17
+ def h2(&content)
18
+ render Heading.new, &content
34
19
  end
35
20
 
36
- def template
37
- raw MARKDOWN.render(@content)
21
+ def a(**attributes, &content)
22
+ super(class: "font-bold text-red-600 underline underline-offset-4", **attributes, &content)
38
23
  end
39
24
  end
40
25
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Nav::Item < Phlex::View
4
+ class Nav::Item < Phlex::HTML
5
5
  def initialize(text, to:, active_page:)
6
6
  @text = text
7
7
  @to = to
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Nav < Phlex::View
4
+ class Nav < Phlex::HTML
5
5
  end
6
6
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Components
4
4
  class Tabs
5
- class Tab < Phlex::View
5
+ class Tab < Phlex::HTML
6
6
  def initialize(name:, checked:)
7
7
  @name = name
8
8
  @checked = checked
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Tabs < Phlex::View
4
+ class Tabs < Phlex::HTML
5
5
  def initialize
6
6
  @index = 1
7
7
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Components
4
- class Title < Phlex::View
4
+ class Title < Phlex::HTML
5
5
  def template(&block)
6
- h1(class: "text-3xl font-semibold my-5") { raw(&block) }
6
+ h1(class: "text-3xl font-semibold my-5", &block)
7
7
  end
8
8
  end
9
9
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pages
4
- class ApplicationPage < Phlex::View
4
+ class ApplicationPage < Phlex::HTML
5
5
  include ::Components
6
6
  end
7
7
  end
@@ -3,7 +3,7 @@
3
3
  module Pages
4
4
  class Helpers < ApplicationPage
5
5
  def template
6
- render Layout.new(title: "Templates in Phlex") do
6
+ render Layout.new(title: "Helpers") do
7
7
  render Markdown.new(<<~MD)
8
8
  # Helpers
9
9
 
@@ -18,7 +18,7 @@ module Pages
18
18
 
19
19
  render Example.new do |e|
20
20
  e.tab "link.rb", <<~RUBY
21
- class Link < Phlex::View
21
+ class Link < Phlex::HTML
22
22
  def initialize(text, to:, active:)
23
23
  @text = text
24
24
  @to = to
@@ -37,7 +37,7 @@ module Pages
37
37
  RUBY
38
38
 
39
39
  e.tab "example.rb", <<~RUBY
40
- class Example < Phlex::View
40
+ class Example < Phlex::HTML
41
41
  def template
42
42
  nav do
43
43
  ul do
@@ -58,7 +58,7 @@ module Pages
58
58
 
59
59
  render Example.new do |e|
60
60
  e.tab "link.rb", <<~RUBY
61
- class Link < Phlex::View
61
+ class Link < Phlex::HTML
62
62
  def initialize(text, to:, active:)
63
63
  @text = text
64
64
  @to = to
@@ -77,7 +77,7 @@ module Pages
77
77
  RUBY
78
78
 
79
79
  e.tab "example.rb", <<~RUBY
80
- class Example < Phlex::View
80
+ class Example < Phlex::HTML
81
81
  def template
82
82
  nav do
83
83
  ul do
@@ -10,7 +10,7 @@ module Pages
10
10
 
11
11
  Phlex comes with an abstract pattern for views that represent collections of resources — lists, grids, tables, etc. Collections have two parts: one part wraps the whole collection, the other part is repeated once for each item in that collection.
12
12
 
13
- When you include `Phlex::Collection` in a `Phlex::View`, the `template` and `initialize` methods are defined for you. You don't need to define these. Instead, you define a `collection_template` and `item_template`.
13
+ When you include `Phlex::Collection` in a `Phlex::HTML`, the `template` and `initialize` methods are defined for you. You don't need to define these. Instead, you define a `collection_template` and `item_template`.
14
14
 
15
15
  ## Collection template
16
16
 
@@ -32,16 +32,6 @@ module Pages
32
32
  end
33
33
  ```
34
34
 
35
- You can also access the predicates `first?` and `last?` and the instance variables `@index`, `@position` and `@collection`.
36
-
37
- ```ruby
38
- def item_template
39
- li **classes(first?: "border-t") do
40
- "\#{@position}/\#{@collection.size} \#{@item}"
41
- end
42
- end
43
- ```
44
-
45
35
  ## Rendering a collection
46
36
 
47
37
  Putting it all together, we can create a `List` view that renders each item in an `<li>`, all wrapped up in an outer `<ul>`.
@@ -51,7 +41,7 @@ module Pages
51
41
 
52
42
  render Example.new do |e|
53
43
  e.tab "list.rb", <<~RUBY
54
- class List < Phlex::View
44
+ class List < Phlex::HTML
55
45
  include Phlex::Collection
56
46
 
57
47
  def collection_template(&content)
@@ -59,15 +49,13 @@ module Pages
59
49
  end
60
50
 
61
51
  def item_template
62
- li **classes(first?: "font-bold") do
63
- "(\#{@position}/\#{@collection.size}) \#{@item}"
64
- end
52
+ li { @item }
65
53
  end
66
54
  end
67
55
  RUBY
68
56
 
69
57
  e.tab "example.rb", <<~RUBY
70
- class Example < Phlex::View
58
+ class Example < Phlex::HTML
71
59
  def template
72
60
  render List.new(
73
61
  collection: ["A", "B", "C"]
@@ -87,12 +75,6 @@ module Pages
87
75
  ```ruby
88
76
  render List.new(item: "A")
89
77
  ```
90
-
91
- If you've used any of the iteration variables and predicates — `first?`, `last?`, `@position`, `@index`, etc. you'll need to pass these manually to simulate this item's position.
92
-
93
- ```ruby
94
- render List.new(item: "A", first: true, position: 1)
95
- ```
96
78
  MD
97
79
  end
98
80
  end
@@ -23,7 +23,7 @@ module Pages
23
23
  This script will:
24
24
 
25
25
  1. update `config/application.rb` to include `/app` in your auto-load paths;
26
- 2. generate `views/application_view.rb`
26
+ 2. generate `views/application_view.rb`.
27
27
 
28
28
  Like `ApplicationRecord`, `ApplicationView` is your base view which all your other views should inherit from.
29
29
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "phlex/rails"
4
+
3
5
  module Pages
4
6
  module Rails
5
7
  class Helpers < ApplicationPage
@@ -35,7 +37,7 @@ module Pages
35
37
  Using these is equvalent to passing the output of the original Rails helpers to `raw`, e.g:
36
38
 
37
39
  ```ruby
38
- raw helpers.javascript_include_tag
40
+ unsafe_raw helpers.javascript_include_tag
39
41
  ```
40
42
 
41
43
  ## Including proxies
@@ -18,7 +18,7 @@ module Pages
18
18
  render Example.new do |e|
19
19
  e.tab "layout.rb", <<~RUBY
20
20
  module Views
21
- class Layout < Phlex::View
21
+ class Layout < Phlex::HTML
22
22
  def initialize(title:)
23
23
  @title = title
24
24
  end
@@ -38,7 +38,7 @@ module Pages
38
38
 
39
39
  e.tab "index.rb", <<~RUBY
40
40
  module Views
41
- class Index < Phlex::View
41
+ class Index < Phlex::HTML
42
42
  def template
43
43
  render Layout.new(title: "Hello") do
44
44
  h1 { "👋" }
@@ -7,7 +7,7 @@ module Pages
7
7
  render Markdown.new <<~MD
8
8
  # Rendering Phlex views in Rails
9
9
 
10
- You can render a `Phlex::View` from your Rails controller actions as well as other views, and even from ActionView / ViewComponent templates.
10
+ You can render a `Phlex::HTML` from your Rails controller actions as well as other views, and even from ActionView / ViewComponent templates.
11
11
 
12
12
  Instead of implicitly rendering an ERB template with automatic access to all your controller instance variables, you need to explicitly render Phlex views from your controller action methods.
13
13