lib/ember/appkit/rails/walker.rb in ember-appkit-rails-0.3.2 vs lib/ember/appkit/rails/walker.rb in ember-appkit-rails-0.4.0

- old
+ new

@@ -1,44 +1,44 @@ -require 'ripper' +require 'parser/current' -class Walker +class Walker < AST::Processor + attr_accessor :found_nodes, :namespace_type + def initialize(resource, path, api_version) @resource = resource @file = File.open(path, 'r+') - content = @file.read - @ast = Ripper.sexp(content) - @lines = content.split("\n") + @content = @file.read + @ast = Parser::CurrentRuby.parse(@content) @api_version = api_version + @found_nodes = [] end - def run - find_api_namespace(@ast) + def handler_missing(node) + walk(node) + end - output = nil - line_number = @lines.index { |line| line =~ /routes\.draw do/ } - - if @write_to - if @write_to.first == :version - output = write_resource - else - output = write_version_namespace do - write_resource - end + def on_block(node) + if is_namespace?(node) + if is_namespace_type?(node, :api) + found_nodes << node + self.namespace_type = :api + walk_namespace(node) + elsif is_namespace_type?(node, "v#{@api_version}".to_sym) + found_nodes << node + self.namespace_type = :version + walk_namespace(node) end - line_number = @write_to.last - 1 else - output = write_api_namespace do - write_version_namespace do - write_resource - end - end + walk(node) end + end - @lines.insert(line_number + 1, output) - @file.rewind - @file.write(@lines.join("\n")) - @file.close + def on_send(node) + if is_resource?(node, @resource.to_sym) + @found_resource = true + found_nodes << node + end end def write_api_namespace " namespace :api do\n#{yield}\n end" end @@ -49,51 +49,80 @@ def write_resource " resources :#{@resource}, except: [:new, :edit]" end - def find_api_namespace(ast) - find_namespace(ast, 'api') do |ast| - find_version_namespace(ast, @api_version) + def invoke! + process(@ast) + if found_nodes.empty? + found_nodes << @ast + end + node = found_nodes.last + begin_pos = node.loc.begin.end_pos - if @write_to.nil? - @write_to = [:api, ast[1][1][2][0]] + output = '' + + if namespace_type + if namespace_type == :version + output = write_resource + else + output = write_version_namespace do + write_resource + end end + else + output = write_api_namespace do + write_version_namespace do + write_resource + end + end + end - # found the first instance of the namespace - # immediately short-circuit - return + @file.rewind + @file.write(@content.insert(begin_pos + 1, output + "\n")) + @file.close + end + + def revoke! + @revoke = true + process(@ast) + return if found_nodes.empty? || @found_resource.nil? + if found_nodes.last.loc.expression + begin_pos = found_nodes.last.loc.expression.begin_pos + end_pos = found_nodes.last.loc.expression.end_pos + else + begin_pos = found_nodes.last.loc.begin.begin_pos + end_pos = found_nodes.last.loc.end.end_pos end + begin_pos = begin_pos - @content[0..begin_pos].reverse.index("\n") + @file.rewind + @file.write @content.sub(@content[begin_pos...end_pos], '') + @file.close end - def find_version_namespace(ast, version) - find_namespace(ast, "v#{version}") do |ast| - @write_to = [:version, ast[1][1][2][0]] + private - # found the first instance of the namespace - # immediately short-circuit - return - end + def is_resource?(node, type) + node.children[1] == :resource && node.children[2].children.first == type.to_sym + end - @write_to + def is_namespace?(node) + node.children.first.children[1] == :namespace end - def find_namespace(ast, name) - walk(ast) do |ast, node| - if node == :method_add_block - flat_ast = ast[1].flatten - if flat_ast.include?('namespace') && flat_ast.include?(name) - yield(ast) - end - end + def is_namespace_type?(node, type) + node.children.first.children[2].children.first == type.to_sym + end + + def walk_namespace(node) + process(node.children[2]) + if @revoke && node.children[2] && node.children[2].children == found_nodes.last.to_a + found_nodes << node end end - def walk(ast, &block) - if ast.is_a?(Array) - ast.each do |node| - yield(ast, node) - walk(node, &block) - end + def walk(node) + node.children.each do |child| + process(child) if child.respond_to?(:to_ast) end end end