lib/goodcheck/config_loader.rb in goodcheck-1.7.1 vs lib/goodcheck/config_loader.rb in goodcheck-2.1.0
- old
+ new
@@ -33,13 +33,40 @@
string
end
})
let :glob, array_or(one_glob)
+ let :var_pattern, any
+ let :variable_pattern, array_or(var_pattern)
+ let :negated_variable_pattern, object(not: variable_pattern)
+
+ let :where, hash(
+ enum(
+ variable_pattern,
+ negated_variable_pattern,
+ literal(true),
+ detector: -> (value) {
+ case
+ when value.is_a?(Hash) && value.key?(:not)
+ negated_variable_pattern
+ when value == true
+ literal(true)
+ else
+ variable_pattern
+ end
+ }
+ )
+ )
+
let :regexp_pattern, object(regexp: string, case_sensitive: boolean?, multiline: boolean?, glob: optional(glob))
let :literal_pattern, object(literal: string, case_sensitive: boolean?, glob: optional(glob))
- let :token_pattern, object(token: string, case_sensitive: boolean?, glob: optional(glob))
+ let :token_pattern, object(
+ token: string,
+ case_sensitive: boolean?,
+ glob: optional(glob),
+ where: optional(where)
+ )
let :pattern, enum(regexp_pattern,
literal_pattern,
token_pattern,
deprecated_regexp_pattern,
@@ -93,16 +120,62 @@
message: string,
justification: optional(array_or(string)),
glob: glob
)
+ let :positive_trigger, object(
+ pattern: array_or(pattern),
+ glob: optional(glob),
+ pass: optional(array_or(string)),
+ fail: optional(array_or(string))
+ )
+
+ let :negative_trigger, object(
+ not: object(pattern: array_or(pattern)),
+ glob: optional(glob),
+ pass: optional(array_or(string)),
+ fail: optional(array_or(string))
+ )
+
+ let :nopattern_trigger, object(
+ glob: glob_obj
+ )
+
+ let :trigger, enum(
+ positive_trigger,
+ negative_trigger,
+ nopattern_trigger,
+ detector: -> (hash) {
+ if hash.is_a?(Hash)
+ case
+ when hash.key?(:pattern)
+ positive_trigger
+ when hash.key?(:not)
+ negative_trigger
+ else
+ nopattern_trigger
+ end
+ end
+ }
+ )
+
+ let :triggered_rule, object(
+ id: string,
+ message: string,
+ justification: optional(array_or(string)),
+ trigger: array_or(trigger)
+ )
+
let :rule, enum(positive_rule,
negative_rule,
nopattern_rule,
+ triggered_rule,
detector: -> (hash) {
if hash.is_a?(Hash)
case
+ when hash[:trigger]
+ triggered_rule
when hash[:pattern]
positive_rule
when hash[:not]
negative_rule
when hash.key?(:glob) && !hash.key?(:pattern) && !hash.key?(:not)
@@ -178,18 +251,80 @@
def load_rule(hash)
Goodcheck.logger.debug "Loading rule: #{hash[:id]}"
id = hash[:id]
- patterns, negated = retrieve_patterns(hash)
+ triggers = retrieve_triggers(hash)
justifications = array(hash[:justification])
- globs = load_globs(array(hash[:glob]))
message = hash[:message].chomp
+
+ Rule.new(id: id, message: message, justifications: justifications, triggers: triggers)
+ end
+
+ def retrieve_triggers(hash)
+ if hash.key?(:trigger)
+ array(hash[:trigger]).map do |trigger|
+ retrieve_trigger(trigger)
+ end
+ else
+ globs = load_globs(array(hash[:glob]))
+ passes = array(hash[:pass])
+ fails = array(hash[:fail])
+
+ if hash.key?(:not) || hash.key?(:pattern)
+ if hash.key?(:not)
+ negated = true
+ patterns = array(hash[:not][:pattern])
+ else
+ negated = false
+ patterns = array(hash[:pattern])
+ end
+
+ glob_patterns, noglob_patterns = patterns.partition {|pat|
+ pat.is_a?(Hash) && pat.key?(:glob)
+ }
+
+ skip_fails = !fails.empty? && !glob_patterns.empty?
+
+ glob_patterns.map do |pat|
+ Trigger.new(
+ patterns: [load_pattern(pat)],
+ globs: load_globs(array(pat[:glob])),
+ passes: passes,
+ fails: [],
+ negated: negated
+ ).by_pattern!.skips_fail_examples!(skip_fails)
+ end.push(
+ Trigger.new(
+ patterns: noglob_patterns.map {|pat| load_pattern(pat) },
+ globs: globs,
+ passes: passes,
+ fails: glob_patterns.empty? ? fails : [],
+ negated: negated
+ ).by_pattern!.skips_fail_examples!(skip_fails)
+ )
+ else
+ [Trigger.new(patterns: [],
+ globs: globs,
+ passes: passes,
+ fails: fails,
+ negated: false).by_pattern!]
+ end
+ end
+ end
+
+ def retrieve_trigger(hash)
+ patterns, negated = retrieve_patterns(hash)
+ globs = load_globs(array(hash[:glob]))
passes = array(hash[:pass])
fails = array(hash[:fail])
- Rule.new(id: id, patterns: patterns, justifications: justifications, globs: globs, message: message, passes: passes, fails: fails, negated: negated)
+ Trigger.new(patterns: patterns,
+ globs: globs,
+ passes: passes,
+ fails: fails,
+ negated: negated)
end
def retrieve_patterns(hash)
if hash.is_a?(Hash) && hash.key?(:not)
negated = true
@@ -217,28 +352,85 @@
end
def load_pattern(pattern)
case pattern
when String
- Pattern.literal(pattern, case_sensitive: true)
+ case (pat = load_string_pattern(pattern))
+ when String
+ Pattern::Literal.new(source: pat, case_sensitive: true)
+ when ::Regexp
+ Pattern::Regexp.new(source: pattern,
+ regexp: pat,
+ multiline: pat.multiline?,
+ case_sensitive: !pat.casefold?)
+ end
when Hash
- globs = load_globs(array(pattern[:glob]))
+ if pattern[:glob]
+ print_warning_once "🌏 Pattern with glob is deprecated: globs are ignored at all."
+ end
+
case
when pattern[:literal]
cs = case_sensitive?(pattern)
literal = pattern[:literal]
- Pattern.literal(literal, case_sensitive: cs, globs: globs)
+ Pattern::Literal.new(source: literal, case_sensitive: cs)
when pattern[:regexp]
regexp = pattern[:regexp]
cs = case_sensitive?(pattern)
multiline = pattern[:multiline]
- Pattern.regexp(regexp, case_sensitive: cs, multiline: multiline, globs: globs)
+ Pattern::Regexp.new(source: regexp, case_sensitive: cs, multiline: multiline)
when pattern[:token]
tok = pattern[:token]
cs = case_sensitive?(pattern)
- Pattern.token(tok, case_sensitive: cs, globs: globs)
+ Pattern::Token.new(source: tok, variables: load_token_vars(pattern[:where]), case_sensitive: cs)
end
end
+ end
+
+ def load_string_pattern(string)
+ if string =~ /\A\/(.*)\/([im]*)\Z/
+ source = $1
+ opts = $2
+ options = 0
+ options |= ::Regexp::IGNORECASE if opts =~ /i/
+ options |= ::Regexp::MULTILINE if opts =~ /m/
+ ::Regexp.new(source, options)
+ else
+ string
+ end
+ end
+
+ def load_token_vars(pattern)
+ case pattern
+ when Hash
+ pattern.each.with_object({}) do |(key, value), hash|
+ hash[key.to_sym] = load_var_pattern(value)
+ end
+ else
+ {}
+ end
+ end
+
+ def load_var_pattern(pattern)
+ if pattern.is_a?(Hash) && pattern[:not]
+ negated = true
+ pattern = pattern[:not]
+ else
+ negated = false
+ end
+
+ pattern = [] if pattern == true
+
+ patterns = array(pattern).map do |pat|
+ case pat
+ when String
+ load_string_pattern(pat)
+ else
+ pat
+ end
+ end
+
+ Pattern::Token::VarPattern.new(patterns: patterns, negated: negated)
end
def case_sensitive?(pattern)
return true if pattern.is_a?(String)
case