From 3c5e3cdef4a2dd1852859c324ff90c9353b69307 Mon Sep 17 00:00:00 2001 From: Vitalii Elenhaupt Date: Sat, 12 Jan 2019 23:19:00 +0200 Subject: [PATCH] Exclude globs as arguments Examples: $ ameba path/to/shard/*.cr !path/to/shard/lib $ ameba . !lib --- bench/check_sources.cr | 2 +- spec/ameba/cli/cmd_spec.cr | 6 +++--- spec/ameba/config_spec.cr | 25 +++++++++++++++-------- spec/ameba/glob_utils_spec.cr | 38 +++++++++++++++++++++++++++++++++++ spec/ameba/runner_spec.cr | 2 +- src/ameba/cli/cmd.cr | 8 ++++---- src/ameba/config.cr | 29 ++++++++++++++++++++------ src/ameba/glob_utils.cr | 37 ++++++++++++++++++++++++++++++++++ src/ameba/runner.cr | 10 +-------- 9 files changed, 125 insertions(+), 32 deletions(-) create mode 100644 spec/ameba/glob_utils_spec.cr create mode 100644 src/ameba/glob_utils.cr diff --git a/bench/check_sources.cr b/bench/check_sources.cr index 8b593604..d66f9603 100644 --- a/bench/check_sources.cr +++ b/bench/check_sources.cr @@ -18,7 +18,7 @@ Benchmark.ips do |x| ].each do |n| config = Ameba::Config.load config.formatter = Ameba::Formatter::BaseFormatter.new - config.files = get_files(n) + config.globs = get_files(n) s = n == 1 ? "" : "s" x.report("#{n} source#{s}") { Ameba.run config } end diff --git a/spec/ameba/cli/cmd_spec.cr b/spec/ameba/cli/cmd_spec.cr index 4be65383..60626a8e 100644 --- a/spec/ameba/cli/cmd_spec.cr +++ b/spec/ameba/cli/cmd_spec.cr @@ -114,9 +114,9 @@ module Ameba::Cli end end - it "accepts unknown args as files" do + it "accepts unknown args as globs" do c = Cli.parse_args %w(source1.cr source2.cr) - c.files.should eq %w(source1.cr source2.cr) + c.globs.should eq %w(source1.cr source2.cr) end it "accepts one unknown arg as explain location if it has correct format" do @@ -132,7 +132,7 @@ module Ameba::Cli it "allows args to be blank" do c = Cli.parse_args [] of String c.formatter.should be_nil - c.files.should be_nil + c.globs.should be_nil c.only.should be_nil c.except.should be_nil c.config.should eq Config::PATH diff --git a/spec/ameba/config_spec.cr b/spec/ameba/config_spec.cr index f2ad3709..367a7691 100644 --- a/spec/ameba/config_spec.cr +++ b/spec/ameba/config_spec.cr @@ -12,28 +12,37 @@ module Ameba it "loads custom config" do config = Config.load config_sample config.should_not be_nil - config.files.should_not be_nil + config.globs.should_not be_nil config.formatter.should_not be_nil end it "loads default config" do config = Config.load config.should_not be_nil - config.files.should_not be_nil + config.globs.should_not be_nil config.formatter.should_not be_nil end end - describe "#files, #files=" do + describe "#globs, #globs=" do config = Config.load config_sample - it "holds source files" do - config.files.should contain "spec/ameba/config_spec.cr" + it "holds source globs" do + config.globs.should contain "spec/ameba/config_spec.cr" end - it "allows to set files" do - config.files = ["file.cr"] - config.files.should eq ["file.cr"] + it "allows to set globs" do + config.globs = ["file.cr"] + config.globs.should eq ["file.cr"] + end + end + + describe "#sources" do + config = Config.load config_sample + + it "returns list of sources" do + config.sources.size.should be > 0 + config.sources.first.should be_a Source end end diff --git a/spec/ameba/glob_utils_spec.cr b/spec/ameba/glob_utils_spec.cr new file mode 100644 index 00000000..7c642ea8 --- /dev/null +++ b/spec/ameba/glob_utils_spec.cr @@ -0,0 +1,38 @@ +require "../spec_helper" + +module Ameba + struct GlobUtilsClass + include GlobUtils + end + + subject = GlobUtilsClass.new + current_file_basename = File.basename(__FILE__) + current_file_path = "spec/ameba/#{current_file_basename}" + + describe GlobUtils do + describe "#find_files_by_globs" do + it "returns a file by globs" do + subject.find_files_by_globs(["**/#{current_file_basename}"]) + .should eq [current_file_path] + end + + it "returns files by globs" do + subject.find_files_by_globs(["**/*_spec.cr"]) + .should contain current_file_path + end + + it "doesn't return rejected globs" do + subject + .find_files_by_globs(["**/*_spec.cr", "!**/#{current_file_basename}"]) + .should_not contain current_file_path + end + end + + describe "#expand" do + it "expands globs" do + subject.expand(["**/#{current_file_basename}"]) + .should eq [current_file_path] + end + end + end +end diff --git a/spec/ameba/runner_spec.cr b/spec/ameba/runner_spec.cr index 2ba83ce6..e2f670da 100644 --- a/spec/ameba/runner_spec.cr +++ b/spec/ameba/runner_spec.cr @@ -4,7 +4,7 @@ module Ameba private def runner(files = [__FILE__], formatter = DummyFormatter.new) config = Config.load config.formatter = formatter - config.files = files + config.globs = files config.update_rule ErrorRule.rule_name, enabled: false diff --git a/src/ameba/cli/cmd.cr b/src/ameba/cli/cmd.cr index 5d049f9f..3149de2a 100644 --- a/src/ameba/cli/cmd.cr +++ b/src/ameba/cli/cmd.cr @@ -8,7 +8,7 @@ module Ameba::Cli def run(args) opts = parse_args args config = Config.load opts.config, opts.colors? - config.files = opts.files + config.globs = opts.globs configure_formatter(config, opts) configure_rules(config, opts) @@ -28,7 +28,7 @@ module Ameba::Cli private class Opts property config = Config::PATH property formatter : Symbol | String | Nil - property files : Array(String)? + property globs : Array(String)? property only : Array(String)? property except : Array(String)? property location_to_explain : NamedTuple(file: String, line: Int32, column: Int32)? @@ -48,7 +48,7 @@ module Ameba::Cli if f.size == 1 && f.first =~ /.+:\d+:\d+/ configure_explain_opts(f.first, opts) else - opts.files = f if f.any? + opts.globs = f if f.any? end end @@ -121,7 +121,7 @@ module Ameba::Cli private def configure_explain_opts(loc, opts) location_to_explain = parse_explain_location(loc) opts.location_to_explain = location_to_explain - opts.files = [location_to_explain[:file]] + opts.globs = [location_to_explain[:file]] opts.formatter = :silent end diff --git a/src/ameba/config.cr b/src/ameba/config.cr index d19c7109..c204acd2 100644 --- a/src/ameba/config.cr +++ b/src/ameba/config.cr @@ -1,4 +1,5 @@ require "yaml" +require "./glob_utils" # A configuration entry for `Ameba::Runner`. # @@ -12,6 +13,8 @@ require "yaml" # By default config loads `.ameba.yml` file in a current directory. # class Ameba::Config + include GlobUtils + AVAILABLE_FORMATTERS = { progress: Formatter::DotFormatter, todo: Formatter::TODOFormatter, @@ -23,7 +26,7 @@ class Ameba::Config PATH = ".ameba.yml" setter formatter : Formatter::BaseFormatter? - setter files : Array(String)? + setter globs : Array(String)? getter rules : Array(Rule::Base) @rule_groups : Hash(String, Array(Rule::Base)) @@ -60,16 +63,30 @@ class Ameba::Config # Returns a list of paths (with wildcards) to files. # Represents a list of sources to be inspected. - # If files are not set, it will return default list of files. + # If globs are not set, it will return default list of files. # # ``` # config = Ameba::Config.load - # config.files = ["**/*.cr"] - # config.files + # config.globs = ["**/*.cr"] + # config.globs # ``` # - def files - @files ||= default_files + def globs + @globs ||= default_files + end + + # Returns a list of sources. + # + # ``` + # config = Ameba::Config.load + # config.sources # => list of default sources + # config.globs = ["**/*.cr"] + # config.sources # => list of sources pointing to files found by the wildcards + # ``` + # + def sources + find_files_by_globs(globs) + .map { |path| Source.new File.read(path), path } end # Returns a formatter to be used while inspecting files. diff --git a/src/ameba/glob_utils.cr b/src/ameba/glob_utils.cr new file mode 100644 index 00000000..0f84c8bf --- /dev/null +++ b/src/ameba/glob_utils.cr @@ -0,0 +1,37 @@ +module Ameba + # Helper module that is utilizes helpers for working with globs. + module GlobUtils + # Returns all files that match specified globs. + # Globs can have wildcards or be rejected: + # + # ``` + # find_files_by_globs(["**/*.cr", "!lib"]) + # ``` + # + def find_files_by_globs(globs) + rejected = rejected_globs(globs) + selected = globs - rejected + + expand(selected) - expand(rejected.map! { |p| p[1..-1] }) + end + + # Expands globs. Globs can point to files or even directories. + # + # ``` + # expand(["spec/*.cr", "src"]) # => all files in src folder + first level specs + # ``` + # + def expand(globs) + globs.map do |glob| + glob += "/**/*.cr" if File.directory?(glob) + Dir[glob] + end.flatten + end + + private def rejected_globs(globs) + globs.select do |glob| + glob.starts_with?('!') && !File.exists?(glob) + end + end + end +end diff --git a/src/ameba/runner.cr b/src/ameba/runner.cr index ace2a285..25479c01 100644 --- a/src/ameba/runner.cr +++ b/src/ameba/runner.cr @@ -37,7 +37,7 @@ module Ameba # ``` # def initialize(config : Config) - @sources = load_sources(config) + @sources = config.sources @formatter = config.formatter @rules = config.rules.select(&.enabled).reject!(&.special?) @@ -115,13 +115,5 @@ module Ameba rule.test(source) end end - - private def load_sources(config) - config.files.map do |wildcard| - wildcard += "/**/*.cr" if File.directory?(wildcard) - Dir[wildcard] - end.flatten - .map { |path| Source.new File.read(path), path } - end end end