rbexy 0.2.3 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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