From d76773e7ae6b47c758601a13b4a6ba000b69acc7 Mon Sep 17 00:00:00 2001 From: Shane da Silva Date: Sat, 13 Sep 2014 22:58:42 -0700 Subject: [PATCH] Add RubyParser helper class Add helper class that encapsulates the `parser` and `astrolabe` gems so that all linters need to do is call `parse_ruby` to get an AST. Change-Id: I3ae6d7899766ff791ca8107593e115aae20ae97e Reviewed-on: http://gerrit.causes.com/42570 Tested-by: jenkins Reviewed-by: Shane da Silva --- haml-lint.gemspec | 1 + lib/haml_lint.rb | 1 + lib/haml_lint/linter.rb | 9 +++++++++ lib/haml_lint/ruby_parser.rb | 29 +++++++++++++++++++++++++++++ spec/haml_lint/ruby_parser_spec.rb | 22 ++++++++++++++++++++++ spec/spec_helper.rb | 1 + 6 files changed, 63 insertions(+) create mode 100644 lib/haml_lint/ruby_parser.rb create mode 100644 spec/haml_lint/ruby_parser_spec.rb diff --git a/haml-lint.gemspec b/haml-lint.gemspec index 159d706c..817b721b 100644 --- a/haml-lint.gemspec +++ b/haml-lint.gemspec @@ -26,5 +26,6 @@ Gem::Specification.new do |s| s.add_dependency 'sysexits', '~> 1.1' s.add_development_dependency 'rspec', '~> 3.0' + s.add_development_dependency 'rspec-its', '~> 1.0' s.add_development_dependency 'rubocop', '0.26.0' # Pin for Travis builds end diff --git a/lib/haml_lint.rb b/lib/haml_lint.rb index e53f98c9..217554d2 100644 --- a/lib/haml_lint.rb +++ b/lib/haml_lint.rb @@ -6,6 +6,7 @@ require 'haml_lint/haml_visitor' require 'haml_lint/lint' require 'haml_lint/linter_registry' +require 'haml_lint/ruby_parser' require 'haml_lint/linter' require 'haml_lint/logger' require 'haml_lint/reporter' diff --git a/lib/haml_lint/linter.rb b/lib/haml_lint/linter.rb index c392002e..794a086a 100644 --- a/lib/haml_lint/linter.rb +++ b/lib/haml_lint/linter.rb @@ -9,6 +9,7 @@ class Linter def initialize(config) @config = config @lints = [] + @ruby_parser = nil end def run(parser) @@ -29,6 +30,14 @@ def add_lint(node, message = nil) @lints << Lint.new(self, parser.filename, node.line, message || self.message) end + # Parse Ruby code into an abstract syntax tree. + # + # @return [AST::Node] + def parse_ruby(source) + @ruby_parser ||= HamlLint::RubyParser.new + @ruby_parser.parse(source) + end + # Remove the surrounding double quotes from a string, ignoring any # leading/trailing whitespace. # diff --git a/lib/haml_lint/ruby_parser.rb b/lib/haml_lint/ruby_parser.rb new file mode 100644 index 00000000..238ed393 --- /dev/null +++ b/lib/haml_lint/ruby_parser.rb @@ -0,0 +1,29 @@ +require 'astrolabe/builder' +require 'parser/current' + +module HamlLint + # Parser for the Ruby language. + # + # This provides a convenient wrapper around the `parser` gem and the + # `astrolabe` integration to go with it. It is intended to be used for linter + # checks that require deep inspection of Ruby code. + class RubyParser + # Creates a reusable parser. + def initialize + @builder = ::Astrolabe::Builder.new + @parser = ::Parser::CurrentRuby.new(@builder) + end + + # Parse the given Ruby source into an abstract syntax tree. + # + # @param source [String] Ruby source code + # @return [Array] syntax tree in the form returned by Parser gem + def parse(source) + buffer = ::Parser::Source::Buffer.new('(string)') + buffer.source = source + + @parser.reset + @parser.parse(buffer) + end + end +end diff --git a/spec/haml_lint/ruby_parser_spec.rb b/spec/haml_lint/ruby_parser_spec.rb new file mode 100644 index 00000000..4e5ffb35 --- /dev/null +++ b/spec/haml_lint/ruby_parser_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe HamlLint::RubyParser do + describe '#parse' do + subject { super().parse(source) } + + context 'when given an empty string' do + let(:source) { '' } + + it { should be_nil } + end + + context 'when given a valid Ruby program' do + let(:source) { "puts 'Hello World'" } + + it { should respond_to :children } + it { should respond_to :type } + it { should respond_to :parent } + its(:type) { should == :send } + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4ebfac38..a1c07439 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,5 @@ require 'haml_lint' +require 'rspec/its' Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }