lib/node_mutation/adapter/parser.rb in node_mutation-1.18.3 vs lib/node_mutation/adapter/parser.rb in node_mutation-1.19.0

- old
+ new

@@ -13,10 +13,53 @@ else node.loc.expression.source end end + # It gets the new source code after evaluating the node. + # @param node [Parser::AST::Node] The node to evaluate. + # @param code [String] The code to evaluate. + # @return [String] The new source code. + # @example + # node = Parser::CurrentRuby.parse('Factory.define :user do; end') + # rewritten_source(node, '{{call.receiver}}').to eq 'Factory' + # + # # index for node array + # node = Parser::CurrentRuby.parse("test(foo, bar)") + # rewritten_source(node, '{{arguments.0}}')).to eq 'foo' + # + # # {key}_pair for hash node + # node = Parser::CurrentRuby.parse("after_commit :do_index, on: :create, if: :indexable?") + # rewritten_source(node, '{{arguments.-1.on_pair}}')).to eq 'on: :create' + # + # # {key}_value for hash node + # node = Parser::CurrentRuby.parse("after_commit :do_index, on: :create, if: :indexable?") + # rewritten_source(node, '{{arguments.-1.on_value}}')).to eq ':create' + # + # # to_single_quote for str node + # node = Parser::CurrentRuby.parse('"foo"') + # rewritten_source(node, 'to_single_quote') => "'foo'" + # + # # to_double_quote for str node + # node = Parser::CurrentRuby.parse("'foo'") + # rewritten_source(node, 'to_double_quote') => '"foo"' + # + # # to_symbol for str node + # node = Parser::CurrentRuby.parse("'foo'") + # rewritten_source(node, 'to_symbol') => ':foo' + # + # # to_lambda_literal for block node + # node = Parser::CurrentRuby.parse('lambda { foobar }') + # rewritten_source(node, 'to_lambda_literal') => '-> { foobar }' + # + # # strip_curly_braces for hash node + # node = Parser::CurrentRuby.parse("{ foo: 'bar' }") + # rewritten_source(node, 'strip_curly_braces') => "foo: 'bar'" + # + # # wrap_curly_braces for hash node + # node = Parser::CurrentRuby.parse("test(foo: 'bar')") + # rewritten_source(node.arguments.first, 'wrap_curly_braces') => "{ foo: 'bar' }" def rewritten_source(node, code) code.gsub(/{{(.+?)}}/m) do old_code = Regexp.last_match(1) evaluated = child_node_by_name(node, old_code) case evaluated @@ -54,10 +97,50 @@ def file_source(node) node.loc.expression.source_buffer.source end + # Get the range of the child node. + # @param node [Parser::AST::Node] The node. + # @param child_name [String] THe name to find child node. + # @return {NodeMutation::Struct::Range} The range of the child node. + # @example + # node = Parser::CurrentRuby.parse('Factory.define :user do; end') + # child_node_range(node, 'caller.receiver') => { start: 0, end: 'Factory'.length } + # + # # node array + # node = Parser::CurrentRuby.parse('foobar arg1, arg2)') + # child_node_range(node, 'arguments') => { start: 'foobar '.length, end: 'foobar arg1, arg2'.length } + # + # # index for node array + # node = Parser::CurrentRuby.parse('foobar(arg1, arg2)') + # child_node_range(node, 'arguments.-1') => { start: 'foobar(arg1, '.length, end: 'foobar(arg1, arg2'.length } + # + # # pips for block node + # node = Parser::CurrentRuby.parse('Factory.define :user do |user|; end') + # child_node_range(node, 'pipes') => { start: 'Factory.deine :user do '.length, end: 'Factory.define :user do |user|'.length } + # + # # parentheses for def and defs node + # node = Parser::CurrentRuby.parse('def foo(bar); end') + # child_node_range(node, 'parentheses') => { start: 'def foo'.length, end: 'def foo(bar)'.length } + # + # # double_colon for const node + # node = Parser::CurrentRuby.parse('Foo::Bar') + # child_node_range(node, 'double_colon') => { start: 'Foo'.length, end: 'Foo::'.length } + # + # # self and dot for defs node + # node = Parser::CurrentRuby.parse('def self.foo(bar); end') + # child_node_range(node, 'self') => { start: 'def '.length, end: 'def self'.length } + # child_node_range(node, 'dot') => { start: 'def self'.length, end: 'def self.'.length } + # + # # dot for send and csend node + # node = Parser::CurrentRuby.parse('foo.bar(test)') + # child_node_range(node, 'self') => { start: 'foo'.length, end: 'foo.'.length } + # + # # parentheses for send and csend node + # node = Parser::CurrentRuby.parse('foo.bar(test)') + # child_node_range(node, 'parentheses') => { start: 'foo.bar'.length, end: 'foo.bar(test)'.length } def child_node_range(node, child_name) direct_child_name, nested_child_name = child_name.to_s.split('.', 2) if node.is_a?(Array) if direct_child_name =~ INDEX_REGEXP @@ -86,31 +169,12 @@ NodeMutation::Struct::Range.new( node.arguments.first.loc.expression.begin_pos - 1, node.arguments.last.loc.expression.end_pos + 1 ) end - when %i[block arguments], %i[def arguments], %i[defs arguments] - if node.arguments.empty? - nil - else - NodeMutation::Struct::Range.new( - node.arguments.first.loc.expression.begin_pos, - node.arguments.last.loc.expression.end_pos - ) - end - when %i[block body], %i[class body], %i[def body], %i[defs body], %i[module body] - if node.body.empty? - nil - else - NodeMutation::Struct::Range.new( - node.body.first.loc.expression.begin_pos, - node.body.last.loc.expression.end_pos - ) - end when %i[class name], %i[const name], %i[cvar name], %i[def name], %i[defs name], %i[gvar name], %i[ivar name], %i[lvar name] - NodeMutation::Struct::Range.new(node.loc.name.begin_pos, node.loc.name.end_pos) when %i[const double_colon] NodeMutation::Struct::Range.new(node.loc.double_colon.begin_pos, node.loc.double_colon.end_pos) when %i[defs dot] NodeMutation::Struct::Range.new(node.loc.operator.begin_pos, node.loc.operator.end_pos) if node.loc.operator @@ -208,11 +272,28 @@ return child_node end if node.respond_to?(direct_child_name) child_node = node.send(direct_child_name) - elsif direct_child_name.include?('(') && direct_child_name.include?(')') - child_node = node.instance_eval(direct_child_name) + elsif direct_child_name == 'to_symbol' && node.type == :str + child_node = ":#{node.to_value}" + elsif direct_child_name == 'to_single_quote' && node.type == :str + child_node = "'#{node.to_value}'" + elsif direct_child_name == 'to_double_quote' && node.type == :str + child_node = "\"#{node.to_value}\"" + elsif direct_child_name == 'to_lambda_literal' && node.type == :block && node.caller.type == :send && node.caller.receiver.nil? && node.caller.message == :lambda + new_source = node.to_source + if node.arguments.size > 1 + new_source = new_source[0...node.arguments.first.loc.expression.begin_pos - 2] + new_source[node.arguments.last.loc.expression.end_pos + 1..-1] + new_source = new_source.sub('lambda', "->(#{node.arguments.map(&:to_source).join(', ')})") + else + new_source = new_source.sub('lambda', '->') + end + child_node = new_source + elsif direct_child_name == 'strip_curly_braces' && node.type == :hash + child_node = node.to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip } + elsif direct_child_name == 'wrap_curly_braces' && node.type == :hash + child_node = "{ #{node.to_source} }" else raise NodeMutation::MethodNotSupported, "#{direct_child_name} is not supported for #{get_source(node)}" end return child_node_by_name(child_node, nested_child_name) if nested_child_name