mutant 0.11.24 → 0.11.26

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fce1f18a168ceb279743d1d6a1bb46226568faba189d4fb6eb7a789a6cd1a4c5
4
- data.tar.gz: 6353bde0559ed50cd5f6111f17b815e072b92c9c70d11b8cc5354b6adf0d790b
3
+ metadata.gz: 7cfde1fc6bf867efdfcaada6e39b084ba28089999da9d3f0c6f68a684f6cce35
4
+ data.tar.gz: 66c43239c831af01f5ff2d9e4fafcaf1f7aaacb29b5bedc47ac859b6e7044aff
5
5
  SHA512:
6
- metadata.gz: 67ad06623a1b89faf01739d36a89b3226bd3f07324ccc6252e7457e1c5fd6000bb14332825dd5df5a9294fdab1338b27b71e3baeffd676f14c8ac6ed6ca8aaa7
7
- data.tar.gz: 68b0a0396ac6d25270d54069ea49eaaa0c70409ec684615673a8f84193ea568d005f3606b51f3868911e05e4695ed04db80532c04b0070130d915dd2a2d371bf
6
+ metadata.gz: a2774dfb906a30402f3a6160bca215a5bfaee671035376406f9858368720a1eacda1237c3cd0794c824c5abd9347cdf8f04ead80b878063a0cadc61c5c044270
7
+ data.tar.gz: 796f8625453e50727e76359e5513cef8f1121dc9166dbb3bc7b4ec7a33114fa08c00b41dddd42f8a6f4dc36cde0a4ff6fd8813309bda54dda81dfaa825fe32c7
@@ -6,7 +6,7 @@ module Mutant
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class Lexer
8
8
  WHITESPACE = [' ', "\t", "\n"].to_set.freeze
9
- STRING_PATTERN = /\A[a-zA-Z][_a-zA-Z0-9]*\z/.freeze
9
+ STRING_PATTERN = /\A[a-zA-Z][_a-zA-Z0-9]*\z/
10
10
 
11
11
  SINGLE_CHAR =
12
12
  {
@@ -5,7 +5,7 @@ module Mutant
5
5
  class Descendants < self
6
6
  include Anima.new(:const_name)
7
7
 
8
- REGEXP = /\Adescendants:(?<const_name>.+)\z/.freeze
8
+ REGEXP = /\Adescendants:(?<const_name>.+)\z/
9
9
 
10
10
  def syntax
11
11
  "descendants:#{const_name}"
@@ -20,11 +20,11 @@ module Mutant
20
20
  '#' => [Matcher::Methods::Instance].freeze
21
21
  }.freeze
22
22
 
23
- METHOD_NAME_PATTERN = /(?<method_name>.+)/.freeze
23
+ METHOD_NAME_PATTERN = /(?<method_name>.+)/
24
24
 
25
25
  private_constant(*constants(false))
26
26
 
27
- REGEXP = /\A#{SCOPE_NAME_PATTERN}#{SCOPE_SYMBOL_PATTERN}#{METHOD_NAME_PATTERN}\z/.freeze
27
+ REGEXP = /\A#{SCOPE_NAME_PATTERN}#{SCOPE_SYMBOL_PATTERN}#{METHOD_NAME_PATTERN}\z/
28
28
 
29
29
  def initialize(*)
30
30
  super
@@ -19,7 +19,7 @@ module Mutant
19
19
 
20
20
  private_constant(*constants(false))
21
21
 
22
- REGEXP = /\A#{SCOPE_NAME_PATTERN}#{SCOPE_SYMBOL_PATTERN}\z/.freeze
22
+ REGEXP = /\A#{SCOPE_NAME_PATTERN}#{SCOPE_SYMBOL_PATTERN}\z/
23
23
 
24
24
  def initialize(*)
25
25
  super
@@ -9,7 +9,7 @@ module Mutant
9
9
 
10
10
  # Recursive namespace expression
11
11
  class Recursive < self
12
- REGEXP = /\A#{SCOPE_NAME_PATTERN}?\*\z/.freeze
12
+ REGEXP = /\A#{SCOPE_NAME_PATTERN}?\*\z/
13
13
 
14
14
  # Initialize object
15
15
  #
@@ -17,7 +17,7 @@ module Mutant
17
17
  def initialize(*)
18
18
  super
19
19
 
20
- @syntax = "#{scope_name}*".freeze # rubocop:disable Style/RedundantFreeze
20
+ @syntax = "#{scope_name}*".freeze
21
21
 
22
22
  @recursion_pattern = Regexp.union(
23
23
  /\A#{scope_name}\z/,
@@ -60,7 +60,7 @@ module Mutant
60
60
  MATCHER = Matcher::Scope
61
61
  private_constant(*constants(false))
62
62
 
63
- REGEXP = /\A#{SCOPE_NAME_PATTERN}\z/.freeze
63
+ REGEXP = /\A#{SCOPE_NAME_PATTERN}\z/
64
64
 
65
65
  # Matcher matcher on expression
66
66
  #
@@ -4,8 +4,8 @@ module Mutant
4
4
 
5
5
  # Abstract base class for match expression
6
6
  class Expression
7
- fragment = /[A-Za-z][A-Za-z\d_]*/.freeze
8
- SCOPE_NAME_PATTERN = /(?<scope_name>#{fragment}(?:#{SCOPE_OPERATOR}#{fragment})*)/.freeze
7
+ fragment = /[A-Za-z][A-Za-z\d_]*/
8
+ SCOPE_NAME_PATTERN = /(?<scope_name>#{fragment}(?:#{SCOPE_OPERATOR}#{fragment})*)/
9
9
  SCOPE_SYMBOL_PATTERN = '(?<scope_symbol>[.#])'
10
10
 
11
11
  private_constant(*constants(false))
@@ -4,50 +4,84 @@ module Mutant
4
4
  module License
5
5
  class Subscription
6
6
  class Commercial < self
7
- class Author
8
- include Anima.new(:email)
9
-
10
- alias_method :to_s, :email
11
- public :to_s
12
- end
7
+ include AbstractType
13
8
 
14
9
  def self.from_json(value)
15
- new(licensed: value.fetch('authors').to_set { |email| Author.new(email: email) })
10
+ {
11
+ 'individual' => Individual,
12
+ 'organization' => Organization
13
+ }.fetch(value.fetch('type', 'individual')).from_json(value)
16
14
  end
17
15
 
18
- def call(world)
19
- candidates = candidates(world)
16
+ class Organization < self
17
+ SUBSCRIPTION_NAME = 'commercial organization'
20
18
 
21
- if (licensed & candidates).any?
22
- success
23
- else
24
- failure(licensed, candidates)
19
+ def self.from_json(value)
20
+ new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
25
21
  end
26
- end
27
22
 
28
- private
23
+ def call(world)
24
+ Repository.load_from_git(world).bind(&method(:check_subscription))
25
+ end
29
26
 
30
- def candidates(world)
31
- git_author(world).merge(commit_author(world))
32
- end
27
+ private
33
28
 
34
- def git_author(world)
35
- capture(world, %w[git config --get user.email])
29
+ def check_subscription(actual)
30
+ if licensed.any? { |repository| actual.any? { |other| repository.allow?(other) } }
31
+ success
32
+ else
33
+ failure(licensed, actual)
34
+ end
35
+ end
36
36
  end
37
37
 
38
- def commit_author(world)
39
- capture(world, %w[git show --quiet --pretty=format:%ae])
40
- end
38
+ class Individual < self
39
+ SUBSCRIPTION_NAME = 'commercial individual'
41
40
 
42
- def capture(world, command)
43
- world
44
- .capture_stdout(command)
45
- .fmap(&:chomp)
46
- .fmap { |email| Author.new(email: email) }
47
- .fmap { |value| Set.new([value]) }
48
- .from_right { Set.new }
49
- end
41
+ class Author
42
+ include Anima.new(:email)
43
+
44
+ alias_method :to_s, :email
45
+ public :to_s
46
+ end
47
+
48
+ def self.from_json(value)
49
+ new(licensed: value.fetch('authors').to_set { |email| Author.new(email: email) })
50
+ end
50
51
 
52
+ def call(world)
53
+ candidates = candidates(world)
54
+
55
+ if (licensed & candidates).any?
56
+ success
57
+ else
58
+ failure(licensed, candidates)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def candidates(world)
65
+ git_author(world).merge(commit_author(world))
66
+ end
67
+
68
+ def git_author(world)
69
+ capture(world, %w[git config --get user.email])
70
+ end
71
+
72
+ def commit_author(world)
73
+ capture(world, %w[git show --quiet --pretty=format:%ae])
74
+ end
75
+
76
+ def capture(world, command)
77
+ world
78
+ .capture_stdout(command)
79
+ .fmap(&:chomp)
80
+ .fmap { |email| Author.new(email: email) }
81
+ .fmap { |value| Set.new([value]) }
82
+ .from_right { Set.new }
83
+ end
84
+ end # Individual
51
85
  end # Commercial
52
86
  end # Subscription
53
87
  end # License
@@ -4,63 +4,14 @@ module Mutant
4
4
  module License
5
5
  class Subscription
6
6
  class Opensource < self
7
- class Repository
8
- include Anima.new(:host, :path)
9
-
10
- REMOTE_REGEXP = /\A[^\t]+\t(?<url>[^ ]+) \((?:fetch|push)\)\n\z/.freeze
11
- GIT_SSH_REGEXP = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}.freeze
12
- GIT_HTTPS_REGEXP = %r{\Ahttps://(?<host>[^/]+)/(?<path>.+?)(?:\.git)?\z}.freeze
13
-
14
- private_constant(*constants(false))
15
-
16
- def to_s
17
- [host, path].join('/')
18
- end
19
-
20
- def self.parse(input)
21
- host, path = *input.split('/', 2).map(&:downcase)
22
- new(host: host, path: path)
23
- end
24
-
25
- def self.parse_remote(input)
26
- match = REMOTE_REGEXP.match(input) or
27
- fail "Unmatched remote line: #{input.inspect}"
28
-
29
- parse_url(match[:url])
30
- end
31
- private_class_method :parse_remote
32
-
33
- def self.parse_url(input)
34
- match = GIT_SSH_REGEXP.match(input) || GIT_HTTPS_REGEXP.match(input)
35
-
36
- unless match
37
- fail "Unmatched git remote URL: #{input.inspect}"
38
- end
39
-
40
- new(host: match[:host], path: match[:path].downcase)
41
- end
42
- private_class_method :parse_url
43
-
44
- def allow?(other)
45
- other.host.eql?(host) && path_match?(other.path)
46
- end
47
-
48
- private
49
-
50
- def path_match?(other_path)
51
- path.eql?(other_path) || (path.end_with?('/*') && other_path.start_with?(path[..-2]))
52
- end
53
- end # Opensource
7
+ SUBSCRIPTION_NAME = 'opensource repository'
54
8
 
55
9
  def self.from_json(value)
56
10
  new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
57
11
  end
58
12
 
59
13
  def call(world)
60
- world
61
- .capture_stdout(%w[git remote --verbose])
62
- .fmap(&method(:parse_remotes))
63
- .bind(&method(:check_subscription))
14
+ Repository.load_from_git(world).bind(&method(:check_subscription))
64
15
  end
65
16
 
66
17
  private
@@ -73,10 +24,6 @@ module Mutant
73
24
  end
74
25
  end
75
26
 
76
- def parse_remotes(input)
77
- input.lines.map(&Repository.method(:parse_remote)).to_set
78
- end
79
-
80
27
  end # Opensource
81
28
  end # Subscription
82
29
  end # License
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ module License
5
+ class Subscription
6
+ class Repository
7
+ include Anima.new(:host, :path)
8
+
9
+ REMOTE_REGEXP = /\A[^\t]+\t(?<url>[^ ]+) \((?:fetch|push)\)\n\z/
10
+ GIT_SSH_REGEXP = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}
11
+ GIT_HTTPS_REGEXP = %r{\Ahttps://(?<host>[^/]+)/(?<path>.+?)(?:\.git)?\z}
12
+ WILDCARD = '/*'
13
+ WILDCARD_RANGE = (..-WILDCARD.length)
14
+
15
+ private_constant(*constants(false))
16
+
17
+ def to_s
18
+ [host, path].join('/')
19
+ end
20
+
21
+ def self.load_from_git(world)
22
+ world
23
+ .capture_stdout(%w[git remote --verbose])
24
+ .fmap(&method(:parse_remotes))
25
+ end
26
+
27
+ def self.parse_remotes(input)
28
+ input.lines.map(&method(:parse_remote)).to_set
29
+ end
30
+ private_class_method :parse_remotes
31
+
32
+ def self.parse(input)
33
+ host, path = *input.split('/', 2).map(&:downcase)
34
+ new(host: host, path: path)
35
+ end
36
+
37
+ def self.parse_remote(input)
38
+ match = REMOTE_REGEXP.match(input) or
39
+ fail "Unmatched remote line: #{input.inspect}"
40
+
41
+ parse_url(match[:url])
42
+ end
43
+ private_class_method :parse_remote
44
+
45
+ def self.parse_url(input)
46
+ match = GIT_SSH_REGEXP.match(input) || GIT_HTTPS_REGEXP.match(input)
47
+
48
+ unless match
49
+ fail "Unmatched git remote URL: #{input.inspect}"
50
+ end
51
+
52
+ new(host: match[:host], path: match[:path].downcase)
53
+ end
54
+ private_class_method :parse_url
55
+
56
+ def allow?(other)
57
+ other.host.eql?(host) && path_match?(other.path)
58
+ end
59
+
60
+ private
61
+
62
+ def path_match?(other_path)
63
+ path.eql?(other_path) || wildcard_match?(path, other_path) || wildcard_match?(other_path, path)
64
+ end
65
+
66
+ def wildcard_match?(left, right)
67
+ left.end_with?(WILDCARD) && right.start_with?(left[WILDCARD_RANGE])
68
+ end
69
+ end # Repository
70
+ end # Subscription
71
+ end # License
72
+ end # Mutant
@@ -54,7 +54,7 @@ module Mutant
54
54
  end
55
55
 
56
56
  def subscription_name
57
- self.class.name.split('::').last.downcase
57
+ self.class::SUBSCRIPTION_NAME
58
58
  end
59
59
 
60
60
  def failure_message(expected, actual)
data/lib/mutant/loader.rb CHANGED
@@ -5,7 +5,7 @@ module Mutant
5
5
  include Anima.new(:binding, :kernel, :source, :subject)
6
6
 
7
7
  FROZEN_STRING_FORMAT = "# frozen_string_literal: true\n%s"
8
- VOID_VALUE_REGEXP = /\A[^:]+:\d+: void value expression/.freeze
8
+ VOID_VALUE_REGEXP = /\A[^:]+:\d+: void value expression/
9
9
 
10
10
  private_constant(*constants(false))
11
11
 
@@ -11,7 +11,7 @@ module Mutant
11
11
  :diffs
12
12
  )
13
13
 
14
- INSPECT_FORMAT = "#<#{self} %s>"
14
+ INSPECT_FORMAT = "#<#{self} %s>".freeze
15
15
  ATTRIBUTE_DELIMITER = ' '
16
16
  ATTRIBUTE_FORMAT = '%s: [%s]'
17
17
  ENUM_DELIMITER = ','
@@ -49,7 +49,7 @@ module Mutant
49
49
 
50
50
  def merge(other)
51
51
  with(
52
- ignore_patterns: other.ignore_patterns,
52
+ ignore_patterns: other.ignore_patterns.any? ? other.ignore_patterns : ignore_patterns,
53
53
  operators: other.operators || operators,
54
54
  timeout: other.timeout || timeout
55
55
  )
@@ -7,7 +7,7 @@ module Mutant
7
7
  include Anima.new(:subject, :node)
8
8
 
9
9
  CODE_DELIMITER = "\0"
10
- CODE_RANGE = (..4).freeze
10
+ CODE_RANGE = (..4)
11
11
 
12
12
  # Mutation identification code
13
13
  #
@@ -5,7 +5,7 @@ module Mutant
5
5
  class Node
6
6
  # Base mutator for index operations
7
7
  class Index < self
8
- NO_VALUE_RANGE = (1..-1).freeze
8
+ NO_VALUE_RANGE = (1..-1)
9
9
  SEND_REPLACEMENTS = %i[at fetch key?].freeze
10
10
 
11
11
  private_constant(*constants(false))
@@ -67,7 +67,7 @@ module Mutant
67
67
 
68
68
  # Mutator for index assignments
69
69
  class Assign < self
70
- REGULAR_RANGE = (1..-2).freeze
70
+ REGULAR_RANGE = (1..-2)
71
71
 
72
72
  private_constant(*constants(false))
73
73
 
@@ -18,7 +18,7 @@ module Mutant
18
18
 
19
19
  # Named value access emitter for instance variables
20
20
  class Ivar < Access
21
- NAME_RANGE = (1..-1).freeze
21
+ NAME_RANGE = (1..-1)
22
22
 
23
23
  handle(:ivar)
24
24
 
@@ -12,7 +12,7 @@ module Mutant
12
12
 
13
13
  define_named_child(:else_body, -1)
14
14
 
15
- RESCUE_INDICES = (1..-2).freeze
15
+ RESCUE_INDICES = (1..-2)
16
16
 
17
17
  private
18
18
 
@@ -7,7 +7,7 @@ module Mutant
7
7
  # Mutator for attribute assignments
8
8
  class AttributeAssignment < self
9
9
 
10
- ATTRIBUTE_RANGE = (..-2).freeze
10
+ ATTRIBUTE_RANGE = (..-2)
11
11
 
12
12
  private_constant(*constants(false))
13
13
 
@@ -4,8 +4,8 @@ module Mutant
4
4
  module Repository
5
5
  class Diff
6
6
  module Ranges
7
- DECIMAL = /(?:0|[1-9]\d*)/.freeze
8
- REGEXP = /\A@@ -(#{DECIMAL})(?:,(#{DECIMAL}))? \+(#{DECIMAL})(?:,(#{DECIMAL}))? @@/.freeze
7
+ DECIMAL = /(?:0|[1-9]\d*)/
8
+ REGEXP = /\A@@ -(#{DECIMAL})(?:,(#{DECIMAL}))? \+(#{DECIMAL})(?:,(#{DECIMAL}))? @@/
9
9
 
10
10
  private_constant(*constants(false))
11
11
 
@@ -6,7 +6,7 @@ module Mutant
6
6
  class Diff
7
7
  include Adamantium, Anima.new(:world, :to)
8
8
 
9
- FORMAT = /\A:\d{6} \d{6} [a-f\d]{40} [a-f\d]{40} [ACDMRTUX]\t(.*)\n\z/.freeze
9
+ FORMAT = /\A:\d{6} \d{6} [a-f\d]{40} [a-f\d]{40} [ACDMRTUX]\t(.*)\n\z/
10
10
 
11
11
  private_constant(*constants(false))
12
12
 
@@ -85,8 +85,8 @@ module Mutant
85
85
  class Path
86
86
  include Adamantium, Anima.new(:world, :to, :path)
87
87
 
88
- DECIMAL = /(?:0|[1-9]\d*)/.freeze
89
- REGEXP = /\A@@ -(#{DECIMAL})(?:,(#{DECIMAL}))? \+(#{DECIMAL})(?:,(#{DECIMAL}))? @@/.freeze
88
+ DECIMAL = /(?:0|[1-9]\d*)/
89
+ REGEXP = /\A@@ -(#{DECIMAL})(?:,(#{DECIMAL}))? \+(#{DECIMAL})(?:,(#{DECIMAL}))? @@/
90
90
 
91
91
  private_constant(*constants(false))
92
92
 
@@ -7,8 +7,8 @@ module Mutant
7
7
 
8
8
  DEFAULT = new(inline_disable: false, mutation: Mutation::Config::DEFAULT)
9
9
 
10
- DISABLE_REGEXP = /(\s|^)mutant:disable(?:\s|$)/.freeze
11
- SYNTAX_REGEXP = /\A(?:#|=begin\n)/.freeze
10
+ DISABLE_REGEXP = /(\s|^)mutant:disable(?:\s|$)/
11
+ SYNTAX_REGEXP = /\A(?:#|=begin\n)/
12
12
 
13
13
  def self.parse(comments:, mutation:)
14
14
  new(
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.24'
5
+ VERSION = '0.11.26'
6
6
  end # Mutant
data/lib/mutant.rb CHANGED
@@ -63,8 +63,8 @@ module Mutant
63
63
 
64
64
  env_key = /[a-zA-Z_\d]+/
65
65
 
66
- ENV_VARIABLE_KEY_VALUE_REGEXP = /\A(?<key>#{env_key}+)=(?<value>.*)\z/.freeze
67
- ENV_VARIABLE_KEY_REGEXP = /\A#{env_key}\z/.freeze
66
+ ENV_VARIABLE_KEY_VALUE_REGEXP = /\A(?<key>#{env_key}+)=(?<value>.*)\z/
67
+ ENV_VARIABLE_KEY_REGEXP = /\A#{env_key}\z/
68
68
 
69
69
  # rubocop:disable Metrics/BlockLength
70
70
  record.call(:require_mutant_lib) do
@@ -251,8 +251,9 @@ module Mutant
251
251
  require 'mutant/range'
252
252
  require 'mutant/license'
253
253
  require 'mutant/license/subscription'
254
- require 'mutant/license/subscription/opensource'
255
254
  require 'mutant/license/subscription/commercial'
255
+ require 'mutant/license/subscription/opensource'
256
+ require 'mutant/license/subscription/repository'
256
257
  require 'mutant/segment'
257
258
  require 'mutant/segment/recorder'
258
259
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.24
4
+ version: 0.11.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-11 00:00:00.000000000 Z
11
+ date: 2023-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -220,6 +220,7 @@ files:
220
220
  - lib/mutant/license/subscription.rb
221
221
  - lib/mutant/license/subscription/commercial.rb
222
222
  - lib/mutant/license/subscription/opensource.rb
223
+ - lib/mutant/license/subscription/repository.rb
223
224
  - lib/mutant/loader.rb
224
225
  - lib/mutant/matcher.rb
225
226
  - lib/mutant/matcher/chain.rb
@@ -372,7 +373,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
372
373
  requirements:
373
374
  - - ">="
374
375
  - !ruby/object:Gem::Version
375
- version: '2.7'
376
+ version: '3.0'
376
377
  required_rubygems_version: !ruby/object:Gem::Requirement
377
378
  requirements:
378
379
  - - ">="