Playback speed
×
Share post
Share post at current time
0:00
/
0:00
Transcript

Synvert now supports the Prism parser

Synvert provides the ability to write code snippets that can automatically rewrite your source code. This video demonstrates that synvert now supports the prism parser

Ruby 3.3 introduced a new standard library, Prism, a parser for the Ruby language. Prism is designed for portability, error tolerance, and maintainability.

I have integrated the Prism parser into Synvert using the Adapter pattern in the node-query and node-mutation gems. This involved implementing a Prism parser adapter, which was straightforward due to the flexible design of these gems.

The Prism adapter for node-query is available here: https://github.com/synvert-hq/node-query-ruby/blob/main/lib/node_query/adapter/prism.rb. It implements methods is_node?, get_node_type, get_source, get_children, get_siblings.

The Prism adapter for node-mutation can be found here: https://github.com/synvert-hq/node-mutation-ruby/blob/main/lib/node_mutation/adapter/prism.rb. This adapter includes methods get_source, rewritten_source, file_source, child_node_range, get_start, get_end, get_start_loc, get_end_loc.

In synvert-core, I simply added a PRISM_PARSER constant for parser configuration. When a snippet uses the PRISM_PARSER, it utilizes Prism to parse the source code and pass the AST nodes to node-query and node-mutation.

Synvert::Rewriter.new 'group', 'name' do
  configure(parser: Synvert::PRISM_PARSER)
end

For example, the ruby/map_and_flatten_to_flat_map snippet is using the PARSER_PARSER, let’s rewrite it to use the PRISM_PARSER. If you are unfamiliar with Prism AST nodes, you can use the Synvert Playground to generate snippets with the Prism parser.

# frozen_string_literal: true

Synvert::Rewriter.new 'ruby', 'map_and_flatten_to_flat_map' do
  configure(parser: Synvert::PRISM_PARSER)

  within_files Synvert::ALL_RUBY_FILES + Synvert::ALL_RAKE_FILES do
    # enum.map do |item|
    #   # do something
    # end.flatten
    # =>
    # enum.flat_map do |item|
    #   # do something
    # end
    find_node '.call_node[receiver=.call_node[name=map][arguments=nil][block=.block_node]][name=flatten][arguments=nil]' do
      group do
        delete :call_operator, :name
        replace 'receiver.name', with: 'flat_map'
      end
    end
  end
end

Run the test command bundle exec rspec spec/ruby/map_and_flatten_to_flat_map_spec.rb to ensure the snippet functions as expected.

Discussion about this podcast