phlex 0.3.2 → 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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +8 -0
  3. data/.rubocop.yml +21 -5
  4. data/Gemfile +26 -12
  5. data/Procfile.dev +3 -0
  6. data/README.md +1 -1
  7. data/Rakefile +3 -5
  8. data/SECURITY.md +1 -1
  9. data/bench.rb +7 -0
  10. data/config/sus.rb +15 -0
  11. data/docs/assets/application.css +6 -0
  12. data/docs/build.rb +17 -10
  13. data/docs/components/callout.rb +1 -1
  14. data/docs/components/code_block.rb +2 -2
  15. data/docs/components/code_span.rb +9 -0
  16. data/docs/components/example.rb +5 -5
  17. data/docs/components/heading.rb +2 -2
  18. data/docs/components/layout.rb +62 -17
  19. data/docs/components/markdown.rb +14 -15
  20. data/docs/components/nav/item.rb +33 -0
  21. data/docs/components/nav.rb +6 -0
  22. data/docs/components/tabs/tab.rb +4 -2
  23. data/docs/components/tabs.rb +1 -1
  24. data/docs/components/title.rb +2 -2
  25. data/docs/page_builder.rb +3 -0
  26. data/docs/pages/application_page.rb +1 -1
  27. data/docs/pages/helpers.rb +97 -0
  28. data/docs/pages/index.rb +6 -17
  29. data/docs/pages/library/collections.rb +83 -0
  30. data/docs/pages/rails/getting_started.rb +53 -0
  31. data/docs/pages/rails/helpers.rb +55 -0
  32. data/docs/pages/rails/layouts.rb +61 -0
  33. data/docs/pages/rails/migrating.rb +37 -0
  34. data/docs/pages/rails/rendering_views.rb +35 -0
  35. data/docs/pages/templates.rb +53 -151
  36. data/docs/pages/testing/capybara.rb +48 -0
  37. data/docs/pages/testing/getting_started.rb +44 -0
  38. data/docs/pages/testing/nokogiri.rb +83 -0
  39. data/docs/pages/testing/rails.rb +17 -0
  40. data/docs/pages/translations.rb +81 -0
  41. data/docs/pages/views.rb +87 -78
  42. data/fixtures/compiler_test_helpers.rb +19 -0
  43. data/fixtures/content.rb +60 -0
  44. data/fixtures/dummy/app/components/comment_component.html.erb +14 -0
  45. data/fixtures/dummy/app/components/comment_component.rb +8 -0
  46. data/fixtures/dummy/app/components/reaction_component.html.erb +3 -0
  47. data/fixtures/dummy/app/components/reaction_component.rb +7 -0
  48. data/fixtures/dummy/app/controllers/comments_controller.rb +4 -0
  49. data/fixtures/dummy/app/views/application_view.rb +8 -0
  50. data/fixtures/dummy/app/views/articles/form.rb +3 -1
  51. data/fixtures/dummy/app/views/card.rb +4 -2
  52. data/fixtures/dummy/app/views/comments/comment.rb +25 -0
  53. data/fixtures/dummy/app/views/comments/index.html.erb +3 -0
  54. data/fixtures/dummy/app/views/comments/reaction.rb +17 -0
  55. data/fixtures/dummy/app/views/comments/show.html.erb +3 -0
  56. data/fixtures/dummy/app/views/heading.rb +1 -1
  57. data/fixtures/layout.rb +5 -5
  58. data/fixtures/page.rb +18 -24
  59. data/fixtures/{test_helper.rb → rails_helper.rb} +3 -7
  60. data/fixtures/standard_element.rb +87 -0
  61. data/fixtures/view_helper.rb +1 -1
  62. data/fixtures/void_element.rb +31 -0
  63. data/lib/generators/phlex/collection/USAGE +8 -0
  64. data/lib/generators/phlex/collection/collection_generator.rb +13 -0
  65. data/lib/generators/phlex/collection/templates/collection.rb.erb +16 -0
  66. data/lib/generators/phlex/controller/USAGE +10 -0
  67. data/lib/generators/phlex/controller/controller_generator.rb +54 -0
  68. data/lib/generators/phlex/controller/templates/controller.rb.erb +10 -0
  69. data/lib/generators/phlex/controller/templates/view.rb.erb +14 -0
  70. data/lib/generators/phlex/layout/USAGE +8 -0
  71. data/lib/generators/phlex/layout/layout_generator.rb +13 -0
  72. data/lib/generators/phlex/layout/templates/layout.rb.erb +31 -0
  73. data/lib/generators/phlex/page/USAGE +8 -0
  74. data/lib/generators/phlex/page/page_generator.rb +13 -0
  75. data/lib/generators/phlex/page/templates/page.rb.erb +13 -0
  76. data/lib/generators/phlex/table/USAGE +8 -0
  77. data/lib/generators/phlex/table/table_generator.rb +14 -0
  78. data/lib/generators/phlex/table/templates/table.rb.erb +11 -0
  79. data/lib/generators/phlex/view/templates/view.rb.erb +7 -1
  80. data/lib/generators/phlex/view/view_generator.rb +9 -1
  81. data/lib/install/phlex.rb +10 -1
  82. data/lib/phlex/block.rb +2 -4
  83. data/lib/phlex/buffered.rb +6 -8
  84. data/lib/phlex/callable.rb +9 -0
  85. data/lib/phlex/collection.rb +33 -0
  86. data/lib/phlex/compiler/elements.rb +49 -0
  87. data/lib/phlex/compiler/generators/content.rb +103 -0
  88. data/lib/phlex/compiler/generators/element.rb +61 -0
  89. data/lib/phlex/compiler/nodes/base.rb +19 -0
  90. data/lib/phlex/compiler/nodes/call.rb +9 -0
  91. data/lib/phlex/compiler/nodes/command.rb +13 -0
  92. data/lib/phlex/compiler/nodes/fcall.rb +18 -0
  93. data/lib/phlex/compiler/nodes/method_add_block.rb +33 -0
  94. data/lib/phlex/compiler/nodes/vcall.rb +9 -0
  95. data/lib/phlex/compiler/optimizer.rb +66 -0
  96. data/lib/phlex/compiler/visitors/base.rb +15 -0
  97. data/lib/phlex/compiler/visitors/file.rb +23 -11
  98. data/lib/phlex/compiler/visitors/stable_scope.rb +28 -0
  99. data/lib/phlex/compiler/visitors/statements.rb +36 -0
  100. data/lib/phlex/compiler/visitors/view.rb +19 -0
  101. data/lib/phlex/compiler/visitors/view_method.rb +59 -0
  102. data/lib/phlex/compiler.rb +23 -3
  103. data/lib/phlex/elements.rb +57 -0
  104. data/lib/phlex/engine.rb +0 -3
  105. data/lib/phlex/helpers.rb +59 -0
  106. data/lib/phlex/html/callbacks.rb +11 -0
  107. data/lib/phlex/html.rb +209 -54
  108. data/lib/phlex/markdown.rb +76 -0
  109. data/lib/phlex/rails/form.rb +67 -0
  110. data/lib/phlex/rails/helpers.rb +118 -0
  111. data/lib/phlex/rails/layout.rb +15 -0
  112. data/lib/phlex/rails.rb +10 -0
  113. data/lib/phlex/renderable.rb +9 -3
  114. data/lib/phlex/table.rb +104 -0
  115. data/lib/phlex/testing/capybara.rb +25 -0
  116. data/lib/phlex/testing/nokogiri.rb +24 -0
  117. data/lib/phlex/testing/rails.rb +19 -0
  118. data/lib/phlex/testing/view_helper.rb +15 -0
  119. data/lib/phlex/translation.rb +23 -0
  120. data/lib/phlex/turbo/frame.rb +21 -0
  121. data/lib/phlex/turbo/stream.rb +18 -0
  122. data/lib/phlex/version.rb +1 -1
  123. data/lib/phlex.rb +22 -24
  124. metadata +112 -15
  125. data/.rspec +0 -1
  126. data/fixtures/compilation/vcall.rb +0 -38
  127. data/lib/phlex/compiler/generators/standard_element.rb +0 -30
  128. data/lib/phlex/compiler/generators/void_element.rb +0 -29
  129. data/lib/phlex/compiler/optimizers/base_optimizer.rb +0 -34
  130. data/lib/phlex/compiler/optimizers/vcall.rb +0 -29
  131. data/lib/phlex/compiler/visitors/base_visitor.rb +0 -19
  132. data/lib/phlex/compiler/visitors/component.rb +0 -28
  133. data/lib/phlex/compiler/visitors/component_method.rb +0 -28
  134. data/lib/phlex/rails/tag_helpers.rb +0 -29
  135. data/lib/phlex/view.rb +0 -223
@@ -1,19 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlex
4
- class Buffered
4
+ class Buffered < SimpleDelegator
5
5
  def initialize(object, buffer:)
6
- @object, @buffer = object, buffer
6
+ super(object)
7
+ @buffer = buffer
7
8
  end
8
9
 
9
- def method_missing(name, *args, **kwargs, &block)
10
- output = @object.public_send(name, *args, **kwargs, &block)
10
+ # Alias output methods to this
11
+ def __output_method__(*args, **kwargs, &block)
12
+ output = __getobj__.public_send(__callee__, *args, **kwargs, &block)
11
13
  @buffer << output if output.is_a? String
12
14
  nil
13
15
  end
14
-
15
- def respond_to_missing?(name)
16
- @object.respond_to?(name)
17
- end
18
16
  end
19
17
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex
4
+ module Callable
5
+ def to_proc
6
+ method(:call).to_proc
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex
4
+ module Collection
5
+ def initialize(collection: nil, item: nil)
6
+ unless collection || item
7
+ raise ArgumentError, "You must pass a collection or an item as a keyword argument."
8
+ end
9
+
10
+ @collection = collection
11
+ @item = item
12
+ end
13
+
14
+ def template
15
+ @item ? item_template : collection_template { yield_items }
16
+ end
17
+
18
+ private
19
+
20
+ def yield_items
21
+ if @item
22
+ raise ArgumentError, "You can only yield_items when rendering a collection. You are currently rendering an item."
23
+ end
24
+
25
+ @collection.each do |item|
26
+ @item = item
27
+ item_template
28
+ end
29
+
30
+ @item = nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Elements
4
+ module VCall
5
+ def format(formatter)
6
+ Phlex::Compiler::Generators::Element.new(
7
+ Phlex::Compiler::Nodes::VCall.new(self),
8
+ formatter: formatter
9
+ ).call
10
+ end
11
+ end
12
+
13
+ module FCall
14
+ def format(formatter)
15
+ Phlex::Compiler::Generators::Element.new(
16
+ Phlex::Compiler::Nodes::FCall.new(self),
17
+ formatter: formatter
18
+ ).call
19
+ end
20
+ end
21
+
22
+ module Command
23
+ def format(formatter)
24
+ Phlex::Compiler::Generators::Element.new(
25
+ Phlex::Compiler::Nodes::Command.new(self),
26
+ formatter: formatter
27
+ ).call
28
+ end
29
+ end
30
+
31
+ module MutatingMethodAddBlock
32
+ def format(formatter)
33
+ Phlex::Compiler::Generators::Element.new(
34
+ Phlex::Compiler::Nodes::MethodAddBlock.new(self),
35
+ formatter: formatter,
36
+ mutating: true
37
+ ).call
38
+ end
39
+ end
40
+
41
+ module MethodAddBlock
42
+ def format(formatter)
43
+ Phlex::Compiler::Generators::Element.new(
44
+ Phlex::Compiler::Nodes::MethodAddBlock.new(self),
45
+ formatter: formatter
46
+ ).call
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex
4
+ class Compiler
5
+ module Generators
6
+ class Content
7
+ def initialize(formatter, content:, mutating: false)
8
+ @formatter = formatter
9
+ @content = content
10
+ @mutating = mutating
11
+ end
12
+
13
+ def call
14
+ return if nil_value?
15
+ return bare_string_value if bare_string_value?
16
+ return symbol_value if symbol_value?
17
+ return numeric_value if numeric_value?
18
+ return variable_value if variable_value?
19
+
20
+ unknown_value
21
+ end
22
+
23
+ private
24
+
25
+ def nil_value?
26
+ case @content
27
+ in SyntaxTree::VarRef[value: SyntaxTree::Kw[value: "nil"]]
28
+ true
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def bare_string_value?
35
+ case @content
36
+ in SyntaxTree::StringLiteral[parts: [SyntaxTree::TStringContent]]
37
+ true
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ def symbol_value?
44
+ @content.is_a?(SyntaxTree::SymbolLiteral)
45
+ end
46
+
47
+ def numeric_value?
48
+ @content.is_a?(SyntaxTree::Int) || @content.is_a?(SyntaxTree::FloatLiteral)
49
+ end
50
+
51
+ def variable_value?
52
+ @content.is_a?(SyntaxTree::VarRef)
53
+ end
54
+
55
+ def bare_string_value
56
+ @formatter.append do |f|
57
+ f.text Hescape.escape_html(
58
+ @content.parts.first.value
59
+ )
60
+ end
61
+ end
62
+
63
+ def symbol_value
64
+ @formatter.append do |f|
65
+ f.text Hescape.escape_html(
66
+ @content.value.value
67
+ )
68
+ end
69
+ end
70
+
71
+ def numeric_value
72
+ @formatter.append do |f|
73
+ f.text Hescape.escape_html(
74
+ @content.value
75
+ )
76
+ end
77
+ end
78
+
79
+ def variable_value
80
+ @formatter.chain_append do |f|
81
+ f.text "Hescape.escape_html("
82
+ @content.format(f)
83
+ f.text ")"
84
+ end
85
+ end
86
+
87
+ def unknown_value
88
+ @formatter.breakable(force: true)
89
+ if @mutating
90
+ @content.format(@formatter)
91
+ else
92
+ @formatter.text "yield_content {"
93
+ @formatter.breakable(force: true)
94
+ @content.format(@formatter)
95
+ @formatter.breakable(force: true)
96
+ @formatter.text "}"
97
+ end
98
+ @formatter.breakable(force: true)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex
4
+ class Compiler
5
+ module Generators
6
+ class Element
7
+ def initialize(node, formatter:, mutating: false)
8
+ @node = node
9
+ @formatter = formatter
10
+ @mutating = mutating
11
+ end
12
+
13
+ def call
14
+ @formatter.append do |f|
15
+ f.text "<"
16
+ f.text tag
17
+ end
18
+
19
+ if @node.arguments&.parts&.any?
20
+ @formatter.chain_append do |f|
21
+ f.text "_attributes("
22
+ @node.arguments.format(@formatter)
23
+ f.text ")"
24
+ end
25
+ end
26
+
27
+ @formatter.append do |f|
28
+ f.text ">"
29
+ end
30
+
31
+ return if void?
32
+
33
+ case @node.content
34
+ in SyntaxTree::Statements[body: [c]]
35
+ Content.new(@formatter, content: c, mutating: @mutating).call
36
+ in nil
37
+ nil
38
+ else
39
+ @node.content.format(@formatter)
40
+ end
41
+
42
+ @formatter.append do |f|
43
+ f.text "</"
44
+ f.text tag
45
+ f.text ">"
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def tag
52
+ HTML::STANDARD_ELEMENTS[@node.name] || HTML::VOID_ELEMENTS[@node.name]
53
+ end
54
+
55
+ def void?
56
+ HTML::VOID_ELEMENTS.key?(@node.name)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class Base
5
+ def initialize(node)
6
+ @node = node
7
+ end
8
+
9
+ attr_accessor :node
10
+
11
+ def arguments
12
+ nil
13
+ end
14
+
15
+ def content
16
+ nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class Call < Base
5
+ def name
6
+ nil
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class Command < Base
5
+ def name
6
+ @node.message.value.to_sym
7
+ end
8
+
9
+ def arguments
10
+ @node.arguments
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class FCall < Base
5
+ def name
6
+ @node.value.value.to_sym
7
+ end
8
+
9
+ def arguments
10
+ case @node.arguments
11
+ in SyntaxTree::Args
12
+ @node.arguments
13
+ in SyntaxTree::ArgParen
14
+ @node.arguments.arguments
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class MethodAddBlock < Base
5
+ def name
6
+ method_call.name
7
+ end
8
+
9
+ def arguments
10
+ method_call.arguments
11
+ end
12
+
13
+ def method_call
14
+ @method_call ||= case @node.call
15
+ in SyntaxTree::FCall
16
+ Phlex::Compiler::Nodes::FCall.new(@node.call)
17
+ in SyntaxTree::Command
18
+ Phlex::Compiler::Nodes::Command.new(@node.call)
19
+ in SyntaxTree::Call
20
+ Phlex::Compiler::Nodes::Call.new(@node.call)
21
+ end
22
+ end
23
+
24
+ def content
25
+ case @node.block
26
+ in SyntaxTree::BraceBlock
27
+ @node.block.statements
28
+ in SyntaxTree::DoBlock
29
+ @node.block.bodystmt.statements
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Nodes
4
+ class VCall < Base
5
+ def name
6
+ @node.value.value.to_sym
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Phlex::Compiler
4
+ class Optimizer
5
+ def initialize(node, compiler:)
6
+ @node = node
7
+ @compiler = compiler
8
+ end
9
+
10
+ def call
11
+ return optimize_element if optimize_element?
12
+
13
+ false
14
+ end
15
+
16
+ private
17
+
18
+ def optimize_element
19
+ case @node
20
+ in Nodes::VCall
21
+ @node.node.extend(Phlex::Compiler::Elements::VCall)
22
+ in Nodes::FCall
23
+ @node.node.extend(Phlex::Compiler::Elements::FCall)
24
+ in Nodes::Command
25
+ @node.node.extend(Phlex::Compiler::Elements::Command)
26
+ in Nodes::MethodAddBlock
27
+ optimize_add_method_block_element
28
+ end
29
+
30
+ true
31
+ end
32
+
33
+ def optimize_add_method_block_element
34
+ visitor = Phlex::Compiler::Visitors::Statements.new(@compiler)
35
+ visitor.visit(@node.content)
36
+
37
+ if visitor.mutating?
38
+ @node.node.extend(Phlex::Compiler::Elements::MutatingMethodAddBlock)
39
+ else
40
+ @node.node.extend(Phlex::Compiler::Elements::MethodAddBlock)
41
+ end
42
+
43
+ Phlex::Compiler::Visitors::ViewMethod.new(@compiler).visit(@node.content)
44
+ end
45
+
46
+ def optimize_element?
47
+ element? && !redefined?
48
+ end
49
+
50
+ def element?
51
+ standard_element? || void_element?
52
+ end
53
+
54
+ def redefined?
55
+ @compiler.redefined?(@node.name)
56
+ end
57
+
58
+ def standard_element?
59
+ Phlex::HTML::STANDARD_ELEMENTS.key?(@node.name)
60
+ end
61
+
62
+ def void_element?
63
+ Phlex::HTML::VOID_ELEMENTS.key?(@node.name)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Visitors
4
+ class Base < SyntaxTree::Visitor
5
+ def initialize(compiler = nil)
6
+ @compiler = compiler
7
+ end
8
+
9
+ private
10
+
11
+ def format(node)
12
+ Phlex::Compiler::Formatter.format("", node)
13
+ end
14
+ end
15
+ end
@@ -1,17 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Phlex
4
- class Compiler
5
- module Visitors
6
- class File < BaseVisitor
7
- visit_method def visit_class(node)
8
- if node.location.start_line == @compiler.line
9
- Visitors::Component.new(@compiler).visit_all(node.child_nodes)
10
- else
11
- super
12
- end
13
- end
3
+ module Phlex::Compiler::Visitors
4
+ class File < Base
5
+ def initialize(compiler)
6
+ @scope = []
7
+ super
8
+ end
9
+
10
+ visit_method def visit_class(node)
11
+ @scope.push(node)
12
+
13
+ if node.location.start_line == @compiler.line
14
+ @compiler.scope = @scope
15
+ View.new(@compiler).visit_all(node.child_nodes)
16
+ else
17
+ super
14
18
  end
19
+
20
+ @scope.pop
21
+ end
22
+
23
+ visit_method def visit_module(node)
24
+ @scope.push(node)
25
+ super
26
+ @scope.pop
15
27
  end
16
28
  end
17
29
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A mixin for visitors that stops them from visiting other scopes.
4
+
5
+ module Phlex::Compiler::Visitors::StableScope
6
+ def visit_class(node)
7
+ nil
8
+ end
9
+
10
+ def visit_module(node)
11
+ nil
12
+ end
13
+
14
+ def visit_brace_block(node)
15
+ nil
16
+ end
17
+
18
+ def visit_do_block(node)
19
+ nil
20
+ end
21
+
22
+ def visit_method_add_block(node)
23
+ node = Phlex::Compiler::Nodes::MethodAddBlock.new(node)
24
+ if node.method_call.name == :render
25
+ visit(node.content)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Visitors
4
+ class Statements < Base
5
+ MUTATING_METHODS = [:raw, :whitespace, :comment, :text, :doctype]
6
+
7
+ include StableScope
8
+
9
+ def mutating?
10
+ !!@mutating
11
+ end
12
+
13
+ visit_method def visit_vcall(node)
14
+ check Phlex::Compiler::Nodes::VCall.new(node)
15
+ end
16
+
17
+ visit_method def visit_fcall(node)
18
+ check Phlex::Compiler::Nodes::FCall.new(node)
19
+ end
20
+
21
+ visit_method def visit_command(node)
22
+ check Phlex::Compiler::Nodes::Command.new(node)
23
+ end
24
+
25
+ visit_method def visit_method_add_block(node)
26
+ check Phlex::Compiler::Nodes::MethodAddBlock.new(node)
27
+ end
28
+
29
+ private
30
+
31
+ def check(node)
32
+ @mutating = true if @compiler.tag_method?(node.name)
33
+ @mutating = true if MUTATING_METHODS.include?(node.name) && !@compiler.redefined?(node.name)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Visitors
4
+ class View < Base
5
+ include StableScope
6
+
7
+ visit_method def visit_def(node)
8
+ visitor = ViewMethod.new(@compiler)
9
+ visitor.visit_all(node.child_nodes)
10
+
11
+ if visitor.optimized_something?
12
+ @compiler.redefine(
13
+ format(node),
14
+ line: node.location.start_line
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlex::Compiler::Visitors
4
+ class ViewMethod < Base
5
+ include StableScope
6
+
7
+ def optimized_something?
8
+ !!@optimized_something
9
+ end
10
+
11
+ visit_method def visit_method_add_block(node)
12
+ return super if node.call.is_a?(SyntaxTree::Call)
13
+
14
+ optimizer = Phlex::Compiler::Optimizer.new(
15
+ Phlex::Compiler::Nodes::MethodAddBlock.new(node),
16
+ compiler: @compiler
17
+ )
18
+
19
+ if optimizer.call
20
+ @optimized_something = true
21
+ end
22
+
23
+ super
24
+ end
25
+
26
+ visit_method def visit_vcall(node)
27
+ optimizer = Phlex::Compiler::Optimizer.new(
28
+ Phlex::Compiler::Nodes::VCall.new(node),
29
+ compiler: @compiler
30
+ )
31
+
32
+ if optimizer.call
33
+ @optimized_something = true
34
+ end
35
+ end
36
+
37
+ visit_method def visit_fcall(node)
38
+ optimizer = Phlex::Compiler::Optimizer.new(
39
+ Phlex::Compiler::Nodes::FCall.new(node),
40
+ compiler: @compiler
41
+ )
42
+
43
+ if optimizer.call
44
+ @optimized_something = true
45
+ end
46
+ end
47
+
48
+ visit_method def visit_command(node)
49
+ optimizer = Phlex::Compiler::Optimizer.new(
50
+ Phlex::Compiler::Nodes::Command.new(node),
51
+ compiler: @compiler
52
+ )
53
+
54
+ if optimizer.call
55
+ @optimized_something = true
56
+ end
57
+ end
58
+ end
59
+ end