rbexy 0.2.3 → 1.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65318a8a1a6c9bc0dc13f0b653dd18df24af2eee0ba7b316c92987becfd10a5b
4
- data.tar.gz: c5bfae261147560bd41b85a3d18b1f672d99294eec70038687315dadeaddcb4a
3
+ metadata.gz: f8c0ebb095f668e7b85fbd14fe770be07fc9f42565b7f71a02e4001a5a0c88c6
4
+ data.tar.gz: 4670b8929fba14f2cdb197eca4c9d72f37ecdef6d1e84d33d43f18bdb09b0a07
5
5
  SHA512:
6
- metadata.gz: 9fec2040704b9d393992b7f9ba73be9ed4de414ba87d021b5aa80daff9b086594807f2ade26b55f3b7c23478d4476040862a019c5bef2538fe82cb5d7e3a20ed
7
- data.tar.gz: 882a81ff03783bfd18e9d2ac09a494ac8cd434e293db3d7a83735c0c5f8fe391a319ea596a31ed3680d1a542e9dbcb656e5fd711f3779a828cea6ff993b37e61
6
+ metadata.gz: 8e9920411ff9198828488d984cfd9e69c67e1ced6600a48d701c01153c4bc06419aaac58d2395ab61676798e9bb0a45137f40788d293fade0c0344c596e60c06
7
+ data.tar.gz: 3da407f7258c3d2f2ef33a157747f6bf0f9ac945ebf801ec064430d80237f802ae7deac36de07a905b055dc9bd7f1958e80774a57f73d036a931a1c4cdac8b81
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
- spec/dummy/log/
1
+ spec/dummy/log/*
2
2
  pkg/
3
- spec/dummy/tmp/
3
+ spec/dummy/tmp/*
4
+ spec/dummy/db/*
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbexy (0.2.3)
5
- actionview (>= 5.0, < 7.0)
6
- activesupport (>= 5.0, < 7.0)
7
- railties (>= 5.0, < 7.0)
4
+ rbexy (1.0.2)
5
+ actionview (>= 6.0, < 7.0)
6
+ activesupport (>= 6.0, < 7.0)
8
7
 
9
8
  GEM
10
9
  remote: https://rubygems.org/
@@ -201,7 +200,7 @@ PLATFORMS
201
200
  DEPENDENCIES
202
201
  guard-rspec (~> 4.7, >= 4.7.3)
203
202
  pry-byebug
204
- rails (>= 5.0, < 7.0)
203
+ rails (>= 6.0, < 7.0)
205
204
  rake
206
205
  rbexy!
207
206
  rspec (~> 3.9)
data/README.md CHANGED
@@ -48,6 +48,8 @@ Add it to your Gemfile and `bundle install`:
48
48
  gem "rbexy"
49
49
  ```
50
50
 
51
+ _From 1.0 onward, we only support Rails 6. If you're using Rails 5, use the 0.x releases._
52
+
51
53
  In `config/application.rb`:
52
54
 
53
55
  ```ruby
@@ -6,6 +6,7 @@ volumes:
6
6
  services:
7
7
  rbexy:
8
8
  build: .
9
+ image: rbexy
9
10
  volumes:
10
11
  - .:/app
11
12
  - bundle:/usr/local/bundle
@@ -13,3 +14,14 @@ services:
13
14
  - $HOME/.gitconfig:/root/.gitconfig:ro
14
15
  - $HOME/.gem/credentials:/root/.gem/credentials
15
16
  working_dir: /app
17
+ dummy:
18
+ image: rbexy
19
+ volumes:
20
+ - .:/app
21
+ - bundle:/usr/local/bundle
22
+ working_dir: /app/spec/dummy/
23
+ command: ./start.sh
24
+ ports:
25
+ - 3000:3000
26
+ environment:
27
+ - RAILS_LOG_STDOUT=1
@@ -6,7 +6,6 @@ module Rbexy
6
6
  autoload :Nodes, "rbexy/nodes"
7
7
  autoload :Runtime, "rbexy/runtime"
8
8
  autoload :HashMash, "rbexy/hash_mash"
9
- autoload :OutputBuffer, "rbexy/output_buffer"
10
9
  autoload :ComponentTagBuilder, "rbexy/component_tag_builder"
11
10
  autoload :ViewContextHelper, "rbexy/view_context_helper"
12
11
  autoload :Configuration, "rbexy/configuration"
@@ -1,27 +1,24 @@
1
1
  require "action_view"
2
+ require "active_support/core_ext/class/attribute"
2
3
 
3
4
  module Rbexy
4
5
  class Component < ActionView::Base
5
- class LookupContext < ActionView::LookupContext
6
- attr_accessor :component_name_stack
7
-
8
- def self.details_hash(context)
9
- context.registered_details.each_with_object({}) do |key, details_hash|
10
- value = key == :locale ? [context.locale] : context.send(key)
11
- details_hash[key] = value
12
- end
13
- end
6
+ autoload :BacktraceCleaner, "rbexy/component/backtrace_cleaner"
14
7
 
15
- # We override any calls to args_for_lookup and set partial=false so that
16
- # the lookup context doesn't automatically add a `_` prefix to the
17
- # template path, since we're using the Rails partial-rendering
18
- # functionality but don't want our templates prefixed with a `_`
19
- def args_for_lookup(name, prefixes, partial, keys, details_options)
20
- partial = false if component_name_stack.include?(name)
21
- super(name, prefixes, partial, keys, details_options)
8
+ class TemplatePath < String
9
+ def to_s
10
+ self
22
11
  end
23
12
  end
24
13
 
14
+ def self.component_name
15
+ name.underscore
16
+ end
17
+
18
+ def component_name
19
+ self.class.component_name
20
+ end
21
+
25
22
  def initialize(view_context, **props)
26
23
  super(
27
24
  view_context.lookup_context,
@@ -45,14 +42,16 @@ module Rbexy
45
42
  end
46
43
 
47
44
  def call
48
- replace_lookup_context
49
- view_renderer.render(self, partial: component_name, &nil)
50
- ensure
51
- restore_lookup_context
45
+ path = TemplatePath.new(component_name)
46
+ template = view_context.lookup_context.find(path)
47
+ template.render(self, {})
48
+ rescue ActionView::Template::Error => error
49
+ error.set_backtrace clean_template_backtrace(error.backtrace)
50
+ raise error
52
51
  end
53
52
 
54
53
  def content
55
- content_block ? view_context.capture(self, &content_block) : ""
54
+ content_block ? content_block.call : ""
56
55
  end
57
56
 
58
57
  def create_context(name, value)
@@ -66,40 +65,13 @@ module Rbexy
66
65
  raise(ContextNotFound, "no parent context `#{name}`")
67
66
  end
68
67
 
69
- def view_renderer
70
- view_context.view_renderer
71
- end
72
-
73
- def component_name
74
- self.class.name.underscore
68
+ def compiled_method_container
69
+ Rbexy::Component
75
70
  end
76
71
 
77
72
  private
78
73
 
79
- attr_reader :view_context, :content_block, :old_lookup_context
80
-
81
- def replace_lookup_context
82
- unless view_renderer.lookup_context.is_a? Rbexy::Component::LookupContext
83
- @old_lookup_context = view_renderer.lookup_context
84
- view_renderer.lookup_context = build_lookup_context(old_lookup_context)
85
- end
86
-
87
- (view_renderer.lookup_context.component_name_stack ||= []) << component_name
88
- end
89
-
90
- def restore_lookup_context
91
- return unless old_lookup_context
92
- view_renderer.lookup_context = old_lookup_context
93
- @old_lookup_context = nil
94
- end
95
-
96
- def build_lookup_context(existing_context)
97
- paths = existing_context.view_paths.dup.unshift(
98
- *Rbexy.configuration.template_paths.map { |p| ActionView::OptimizedFileSystemResolver.new(p) }
99
- )
100
-
101
- LookupContext.new(paths, LookupContext.details_hash(existing_context))
102
- end
74
+ attr_reader :view_context, :content_block
103
75
 
104
76
  def method_missing(meth, *args, &block)
105
77
  if view_context.respond_to?(meth)
@@ -108,5 +80,10 @@ module Rbexy
108
80
  super
109
81
  end
110
82
  end
83
+
84
+ def clean_template_backtrace(backtrace)
85
+ return backtrace if Rbexy.configuration.debug
86
+ BacktraceCleaner.new(backtrace).call
87
+ end
111
88
  end
112
89
  end
@@ -0,0 +1,59 @@
1
+ module Rbexy
2
+ class Component
3
+ class BacktraceCleaner
4
+ attr_reader :backtrace
5
+
6
+ def initialize(backtrace)
7
+ @backtrace = backtrace
8
+ @found_templates = {}
9
+ end
10
+
11
+ def call
12
+ backtrace
13
+ .reject(&method(:internal_implementation_detail?))
14
+ .map(&method(:strip_rbx_internals_block_mention))
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :found_templates
20
+
21
+ def internal_implementation_detail?(line)
22
+ if template = template_name_if_rbx_internals(line)
23
+ redundant_internal_block?(line, template)
24
+ else
25
+ internal_method_call?(line)
26
+ end
27
+ end
28
+
29
+ def internal_method_call?(line)
30
+ line =~ /lib\/rbexy\/.*\.rb/ ||
31
+ line =~ /lib\/action_view\/.*\.rb/ ||
32
+ line =~ /lib\/active_support\/notifications\.rb/
33
+ end
34
+
35
+ def redundant_internal_block?(line, template)
36
+ if found_templates[template]
37
+ true
38
+ else
39
+ found_templates[template] = true
40
+ false
41
+ end
42
+ end
43
+
44
+ def strip_rbx_internals_block_mention(line)
45
+ if template_name_if_rbx_internals(line)
46
+ line.gsub(/block (\(\d+ levels\))? ?in /, "")
47
+ else
48
+ line
49
+ end
50
+ end
51
+
52
+ def template_name_if_rbx_internals(line)
53
+ if /\/(?<template>[^\/]*)\.rbx:\d+:in `(block |_)/ =~ line
54
+ template
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -2,6 +2,8 @@ module Rbexy
2
2
  class Configuration
3
3
  attr_accessor :component_provider
4
4
  attr_accessor :template_paths
5
+ attr_accessor :enable_context
6
+ attr_accessor :debug
5
7
 
6
8
  def template_paths
7
9
  @template_paths ||= []
@@ -22,7 +22,7 @@ module Rbexy
22
22
  text_content: /[^<{#]+/,
23
23
  comment: /^\p{Blank}*#.*(\n|\z)/,
24
24
  whitespace: /\s+/,
25
- attr: /[A-Za-z0-9\-_\.]+/,
25
+ attr: /[A-Za-z0-9\-_\.:]+/,
26
26
  open_attr_splat: /{\*\*/,
27
27
  attr_assignment: /=/,
28
28
  double_quote: /"/,
@@ -237,7 +237,6 @@ module Rbexy
237
237
  end
238
238
 
239
239
  def potential_expression_inner_tag
240
- # binding.pry
241
240
  if self.curr_expr =~ Patterns.expression_internal_tag_prefixes
242
241
  tokens << [:EXPRESSION_BODY, curr_expr]
243
242
  self.curr_expr = ""
@@ -18,11 +18,7 @@ module Rbexy
18
18
  end
19
19
 
20
20
  def compile
21
- [
22
- "Rbexy::OutputBuffer.new.tap { |output|",
23
- children.map(&:compile).map { |c| "output << (#{c})"}.join(";"),
24
- "}.html_safe"
25
- ].join(" ")
21
+ "#{children.map(&:compile).map { |c| "@output_buffer << rbexy_prep_output(#{c})"}.join(";")};@output_buffer"
26
22
  end
27
23
  end
28
24
 
@@ -75,23 +71,24 @@ module Rbexy
75
71
  base_tag = "rbexy_tag.#{Util.safe_tag_name(name)}(#{compile_members})"
76
72
  tag = if children.length > 0
77
73
  [
78
- "#{base_tag} {",
79
- "Rbexy::OutputBuffer.new.tap { |output|",
80
- children.map(&:compile).map { |c| "output << (#{c})"}.join(";"),
81
- "}.html_safe",
82
- "}"
83
- ].join(" ")
74
+ "#{base_tag} { capture {",
75
+ children.map(&:compile).map { |c| "@output_buffer << rbexy_prep_output(#{c})" }.join(";"),
76
+ "} }"
77
+ ].join
84
78
  else
85
79
  base_tag
86
- end
80
+ end + ".html_safe"
87
81
 
88
- [
89
- "Rbexy::OutputBuffer.new.tap { |output|",
90
- "rbexy_context.push({}) if defined?(Rbexy::Component) && self.is_a?(Rbexy::Component);",
91
- "output << (#{tag});",
92
- "rbexy_context.pop if defined?(Rbexy::Component) && self.is_a?(Rbexy::Component);",
93
- "}.html_safe"
94
- ].join(" ")
82
+ if Rbexy.configuration.enable_context
83
+ [
84
+ "(",
85
+ "rbexy_context.push({});",
86
+ "#{tag}.tap { rbexy_context.pop }",
87
+ ")"
88
+ ].join
89
+ else
90
+ tag
91
+ end
95
92
  end
96
93
 
97
94
  def compile_members
@@ -4,5 +4,6 @@ module Rbexy
4
4
  module Rails
5
5
  autoload :Engine, "rbexy/rails/engine"
6
6
  autoload :ControllerHelper, "rbexy/rails/controller_helper"
7
+ autoload :ComponentTemplateResolver, "rbexy/rails/component_template_resolver"
7
8
  end
8
9
  end
@@ -0,0 +1,35 @@
1
+ require "action_view"
2
+
3
+ module Rbexy
4
+ module Rails
5
+ class ComponentTemplateResolver < ActionView::FileSystemResolver
6
+ # Rails 6 requires us to override `_find_all` in order to hook
7
+ def _find_all(name, prefix, partial, details, key, locals)
8
+ find_templates(name, prefix, partial, details, locals)
9
+ end
10
+
11
+ # Rails 5 only requires `find_templates` (which tbh is the proper way
12
+ # to implement subclasses of ActionView::Resolver)
13
+ def find_templates(name, prefix, partial, details, locals = [])
14
+ return [] unless name.is_a? Rbexy::Component::TemplatePath
15
+
16
+ templates_path = File.join(@path, prefix, name)
17
+ extensions = details[:handlers].join(",")
18
+
19
+ Dir["#{templates_path}.*{#{extensions}}"].map do |template_path|
20
+ source = File.binread(template_path)
21
+ handler = ActionView::Template.handler_for_extension(File.extname(template_path)[1..-1])
22
+ virtual_path = ["rbexy_component", prefix, name].join("/")
23
+
24
+ ActionView::Template.new(
25
+ source,
26
+ template_path,
27
+ handler,
28
+ locals: [],
29
+ virtual_path: virtual_path
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,20 @@
1
+ require "active_support/concern"
2
+
3
+ module Rbexy
4
+ module Rails
1
5
  module ControllerHelper
6
+ extend ActiveSupport::Concern
7
+
2
8
  def rbexy_component_provider; end
9
+
10
+ class_methods do
11
+ def inherited(klass)
12
+ super
13
+ Rbexy.configuration.template_paths.each do |path|
14
+ prepend_view_path(Rbexy::Rails::ComponentTemplateResolver.new(path))
15
+ end
16
+ end
17
+ end
3
18
  end
19
+ end
20
+ end
@@ -24,6 +24,7 @@ module Rbexy
24
24
  require "rbexy/component_providers/rbexy_provider"
25
25
  config.component_provider = Rbexy::ComponentProviders::RbexyProvider.new
26
26
  config.template_paths << ::Rails.root.join("app", "components")
27
+ config.enable_context = true
27
28
  end
28
29
  end
29
30
  end
@@ -34,6 +34,7 @@ module Rbexy
34
34
  end
35
35
 
36
36
  def evaluate(code)
37
+ @output_buffer = ActionView::OutputBuffer.new
37
38
  instance_eval(code)
38
39
  rescue => e
39
40
  e.set_backtrace(e.backtrace.map { |l| l.gsub("(eval)", "(rbx template string)") })
@@ -1,3 +1,3 @@
1
1
  module Rbexy
2
- VERSION = "0.2.3"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -7,5 +7,17 @@ module Rbexy
7
7
  def rbexy_context
8
8
  @rbexy_context ||= [{}]
9
9
  end
10
+
11
+ def rbexy_prep_output(*value)
12
+ return if value.length == 0
13
+ value = value.first
14
+
15
+ value = rbexy_is_html_safe_array?(value) ? value.join.html_safe : value
16
+ [nil, false].include?(value) ? "" : value.to_s
17
+ end
18
+
19
+ def rbexy_is_html_safe_array?(value)
20
+ value.is_a?(Array) && value.all? { |v| v.respond_to?(:html_safe?) && v.html_safe? }
21
+ end
10
22
  end
11
23
  end
@@ -25,11 +25,10 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.add_dependency "activesupport", ">= 5.0", "< 7.0"
29
- spec.add_dependency "actionview", ">= 5.0", "< 7.0"
30
- spec.add_dependency "railties", ">= 5.0", "< 7.0"
28
+ spec.add_dependency "activesupport", ">= 6.0", "< 7.0"
29
+ spec.add_dependency "actionview", ">= 6.0", "< 7.0"
31
30
 
32
- spec.add_development_dependency "rails", ">= 5.0", "< 7.0"
31
+ spec.add_development_dependency "rails", ">= 6.0", "< 7.0"
33
32
  spec.add_development_dependency "rspec", "~> 3.9"
34
33
  spec.add_development_dependency "guard-rspec", "~> 4.7", ">= 4.7.3"
35
34
  spec.add_development_dependency "rspec-rails", "~> 4.0", ">= 4.0.1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbexy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Giancola
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-24 00:00:00.000000000 Z
11
+ date: 2020-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '6.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '7.0'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.0'
29
+ version: '6.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '7.0'
@@ -36,7 +36,7 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '5.0'
39
+ version: '6.0'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '7.0'
@@ -46,27 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: '5.0'
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '7.0'
53
- - !ruby/object:Gem::Dependency
54
- name: railties
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- version: '5.0'
60
- - - "<"
61
- - !ruby/object:Gem::Version
62
- version: '7.0'
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '5.0'
49
+ version: '6.0'
70
50
  - - "<"
71
51
  - !ruby/object:Gem::Version
72
52
  version: '7.0'
@@ -76,7 +56,7 @@ dependencies:
76
56
  requirements:
77
57
  - - ">="
78
58
  - !ruby/object:Gem::Version
79
- version: '5.0'
59
+ version: '6.0'
80
60
  - - "<"
81
61
  - !ruby/object:Gem::Version
82
62
  version: '7.0'
@@ -86,7 +66,7 @@ dependencies:
86
66
  requirements:
87
67
  - - ">="
88
68
  - !ruby/object:Gem::Version
89
- version: '5.0'
69
+ version: '6.0'
90
70
  - - "<"
91
71
  - !ruby/object:Gem::Version
92
72
  version: '7.0'
@@ -224,6 +204,7 @@ files:
224
204
  - example.rb
225
205
  - lib/rbexy.rb
226
206
  - lib/rbexy/component.rb
207
+ - lib/rbexy/component/backtrace_cleaner.rb
227
208
  - lib/rbexy/component_providers/namespaced_rbexy_provider.rb
228
209
  - lib/rbexy/component_providers/rbexy_provider.rb
229
210
  - lib/rbexy/component_providers/view_component_provider.rb
@@ -232,9 +213,9 @@ files:
232
213
  - lib/rbexy/hash_mash.rb
233
214
  - lib/rbexy/lexer.rb
234
215
  - lib/rbexy/nodes.rb
235
- - lib/rbexy/output_buffer.rb
236
216
  - lib/rbexy/parser.rb
237
217
  - lib/rbexy/rails.rb
218
+ - lib/rbexy/rails/component_template_resolver.rb
238
219
  - lib/rbexy/rails/controller_helper.rb
239
220
  - lib/rbexy/rails/engine.rb
240
221
  - lib/rbexy/runtime.rb
@@ -1,8 +0,0 @@
1
- module Rbexy
2
- class OutputBuffer < String
3
- def <<(content)
4
- value = content.is_a?(Array) ? content.join : content
5
- super([nil, false].include?(value) ? "" : value.to_s)
6
- end
7
- end
8
- end