lib/ember/appkit/rails/walker.rb
require 'parser/current'
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 = Parser::CurrentRuby.parse(@content)
@api_version = api_version
@found_nodes = []
end
def handler_missing(node)
walk(node)
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
else
walk(node)
end
end
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
def write_version_namespace
" namespace :v#{@api_version} do\n#{yield}\n end"
end
def write_resource
" resources :#{@resource}, except: [:new, :edit]"
end
def invoke!
process(@ast)
if found_nodes.empty?
found_nodes << @ast
end
node = found_nodes.last
begin_pos = node.loc.begin.end_pos
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
@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
private
def is_resource?(node, type)
node.children[1] == :resource && node.children[2].children.first == type.to_sym
end
def is_namespace?(node)
node.children.first.children[1] == :namespace
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(node)
node.children.each do |child|
process(child) if child.respond_to?(:to_ast)
end
end
end