Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support providing a custom ERB parser class #67

Merged
merged 3 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ Packwerk reads from the `packwerk.yml` configuration file in the root directory.
| load_paths | All application autoload paths | list of load paths |
| custom_associations | N/A | list of custom associations, if any |

### Using a custom ERB parser

You can specify a custom ERB parser if needed. For example, if you're using `<%graphql>` tags from https://github.com/github/graphql-client in your ERBs, you can use a custom parser subclass to comment them out so that Packwerk can parse the rest of the file:

```ruby
class CustomParser < Packwerk::Parsers::Erb
def parse_buffer(buffer, file_path:)
preprocessed_source = buffer.source

# Comment out <%graphql ... %> tags. They won't contain any object
# references anyways.
preprocessed_source = preprocessed_source.gsub(/<%graphql/, "<%#")

preprocessed_buffer = Parser::Source::Buffer.new(file_path)
preprocessed_buffer.source = preprocessed_source
super(preprocessed_buffer, file_path: file_path)
end
end

Packwerk::Parsers::Factory.instance.erb_parser_class = CustomParser
```

### Inflections

Expand Down
4 changes: 4 additions & 0 deletions lib/packwerk/parsers/erb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def initialize(parser_class: BetterHtml::Parser, ruby_parser: Ruby.new)
def call(io:, file_path: "<unknown>")
buffer = Parser::Source::Buffer.new(file_path)
buffer.source = io.read
parse_buffer(buffer, file_path: file_path)
end

def parse_buffer(buffer, file_path:)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split this to allow subclasses to implement #parse_buffer without concerning themselves with the actual file read.

parser = @parser_class.new(buffer, template_language: :html)
to_ruby_ast(parser.ast, file_path)
rescue EncodingError => e
Expand Down
11 changes: 10 additions & 1 deletion lib/packwerk/parsers/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ def for_path(path)
when RUBY_REGEX
@ruby_parser ||= Ruby.new
when ERB_REGEX
@erb_parser ||= Erb.new
@erb_parser ||= erb_parser_class.new
end
end

def erb_parser_class
@erb_parser_class || Erb
end

def erb_parser_class=(klass)
@erb_parser_class = klass
@erb_parser = nil
end
end
end
end
12 changes: 12 additions & 0 deletions test/unit/parsers/factory_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ class FactoryTest < Minitest::Test
assert_instance_of(Parsers::Erb, factory.for_path("foo.html.erb"))
assert_instance_of(Parsers::Erb, factory.for_path("foo.md.erb"))
assert_instance_of(Parsers::Erb, factory.for_path("/sub/directory/foo.erb"))

fake_class = Class.new
with_erb_parser_class(fake_class) do
assert_instance_of(fake_class, factory.for_path("foo.html.erb"))
end
end

test "#for_path gives nil for unknown path" do
Expand All @@ -33,6 +38,13 @@ class FactoryTest < Minitest::Test

private

def with_erb_parser_class(klass)
factory.erb_parser_class = klass
yield
ensure
factory.erb_parser_class = nil
end

def factory
Parsers::Factory.instance
end
Expand Down