Repository: prettier/plugin-ruby

Issue #50: Incorrect argument formatting for HEREDOC
Created: 2019-02-08T04:37:17Z
I have an easily reproducible error case for you, hope you dont mind 😄
With this input:
require 'set'

module Delegation
  class DelegationError < NoMethodError; end

  RUBY_RESERVED_KEYWORDS = %w[alias and BEGIN begin break case class def defined? do
                              else elsif END end ensure false for if in module next nil not or redo rescue retry
                              return self super then true undef unless until when while yield].freeze
  DELEGATION_RESERVED_KEYWORDS = %w[_ arg args block].freeze
  DELEGATION_RESERVED_METHOD_NAMES = Set.new(
    RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
  ).freeze

  def delegate_missing_to(target)
    target = target.to_s
    target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)

    module_eval <<-RUBY, __FILE__, __LINE__ + 1
      def respond_to_missing?(name, include_private = false)
        # It may look like an oversight, but we deliberately do not pass
        # +include_private+, because they do not get delegated.

        #{target}.respond_to?(name) || super
      end

      def method_missing(method, *args, &block)
        if #{target}.respond_to?(method)
          #{target}.public_send(method, *args, &block)
        else
          begin
            super
          rescue NoMethodError
            if #{target}.nil?
              raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
            else
              raise
            end
          end
        end
      end
    RUBY
  end
end
prettier-ruby creates syntactically incorrect output:
# frozen_string_literal: true

require 'set'

module Delegation
  class DelegationError < NoMethodError; end

  RUBY_RESERVED_KEYWORDS = %w[
    alias
    and
    BEGIN
    begin
    break
    case
    class
    def
    defined?
    do
    else
    elsif
    END
    end
    ensure
    false
    for
    if
    in
    module
    next
    nil
    not
    or
    redo
    rescue
    retry
    return
    self
    super
    then
    true
    undef
    unless
    until
    when
    while
    yield
  ]
    .freeze
  DELEGATION_RESERVED_KEYWORDS = %w[_ arg args block].freeze
  DELEGATION_RESERVED_METHOD_NAMES =
    Set.new(RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS).freeze

  def delegate_missing_to(target)
    target = target.to_s
    if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
      target = "self.#{target}"
    end

    module_eval <<-RUBY
                      def respond_to_missing?(name, include_private = false)
        # It may look like an oversight, but we deliberately do not pass
        # +include_private+, because they do not get delegated.

        #{target}.respond_to?(name) || super
      end

      def method_missing(method, *args, &block)
        if #{target}.respond_to?(method)
          #{target}.public_send(method, *args, &block)
        else
          begin
            super
          rescue NoMethodError
            if #{target}.nil?
              raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
            else
              raise
            end
          end
        end
      end
    RUBY,
                __FILE__,
                __LINE__ + 1
  end
end

Duplicate issue #75: Running prettier twice on the same file crashes
Created: 2019-02-11T01:04:30Z
Input
https://github.com/rails/rails/blob/9099d66bc38f2e560613258f520d46df624d99c0/activesupport/lib/active_support/configurable.rb
Current output
       # Compiles reader methods so we don't have to go through method_missing.
       def self.compile_methods!(keys)
         keys.reject { |m| method_defined?(m) }.each do |key|
-          class_eval <<-RUBY, __FILE__, __LINE__ + 1
-            def #{key}; _get(#{key.inspect}); end
-          RUBY
+          class_eval <<-RUBY
+                                 def #{key}; _get(#{key
+                       .inspect}); end
+          RUBY,
+                     __FILE__,
+                     __LINE__ + 1
         end
       end
     end
Note that this code crashes when running prettier again on the same file:

src/ripper.rb:33:in block in parse': undefined method []' for nil:NilClass (NoMethodError)

Expected output
Not to crash
Reproduction
Run prettier with --write twice on the Rail's file, or once with --debug-check

yarn prettier --debug-check --plugin=. --parser=ruby ../rails/activesupport/lib/active_support/configurable.rb

Closing comment (2019-02-11T02:07:47Z): Yeah, this is the same as #50 - we've gotta address heredoc handling. Gonna close this as a dup of that one