condition_coverage 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b23a1bb5174201acad8b95876d179f5d7e818bea50eeca8799e189e41ae4014
4
- data.tar.gz: 0527c568699e2fb994438308eeeafaf7b1183a3cbbb632d85efe60e7c482acbd
3
+ metadata.gz: e0b1aba7a743838c35d3b4d139b40efebafd48edef44b82ffc48f7c045eb6861
4
+ data.tar.gz: '074496c6beaf83b9c6ec438019eb20e7b4f8231230ba94cd5e7a87cc2dc01eb1'
5
5
  SHA512:
6
- metadata.gz: 0d7593c42bfeb6e8a319e92740786829d7be675e5c2c66a9b96ced249cc811c5a8dc3ae0cae05d40afec05d650fc0d11e75db4171924a25435c88750967d1a41
7
- data.tar.gz: 7831a347fae127eb253f7d806eb2d7ba3594718266d952da88e0030fd66027ab09d4936598efb04a23eef53c0ed070c082216aa4491964ae4ea96c3991652839
6
+ metadata.gz: debb313edef170467b8146405bc25f212b852798c19492b20699a111d255c05015ade7357a90cc9666e9a5642674fa31a0dcea3f930978bd2ef8bad2b37cab04
7
+ data.tar.gz: e90aa8e71930f57e5e50b5f70155d7166ace8741f300abb7092bafbb3d47bafaaa3ce409cfe7102fc1795dfe7cea5224961a8497e027a617351b371010d83432
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Condition coverage for Ruby, to run alongside SimpleCov's line and branch
4
4
  coverage.
5
5
 
6
- Status: 0.0.2 covers `&&`, `||`, `and` and `or`: each leaf operand of a
6
+ Status: 0.0.3 covers `&&`, `||`, `and` and `or`: each leaf operand of a
7
7
  condition, however its operators are chained, nested or grouped. Decisions
8
8
  hidden inside calls come next (see Roadmap).
9
9
 
@@ -96,11 +96,15 @@ the file:
96
96
  ```ruby
97
97
  ok?(id) && new?(id)
98
98
  # compiles as
99
- ConditionCoverage.record("k.rb:2:2", 0, (ok?(id))) && ConditionCoverage.record("k.rb:2:2", 1, (new?(id)))
99
+ ConditionCoverage.record("k.rb:2:2", 0, ok?(id)) && ConditionCoverage.record("k.rb:2:2", 1, new?(id))
100
100
  ```
101
101
 
102
- Each operand gets parentheses of its own, since one such as `ok? id` (after
103
- `and`) is not valid as a bare argument.
102
+ A command call such as `ok? id` (after `and`) is not valid as a bare
103
+ argument, so that operand alone gets parentheses of its own. No other operand
104
+ does: parentheses make a statement, and a statement on a continuation line
105
+ gives that line a line-coverage count of its own, which would change
106
+ SimpleCov's line totals. With that one exception, an instrumented file has
107
+ the same relevant lines as an uninstrumented one.
104
108
 
105
109
  `record` counts whether the operand was truthy or falsy and returns it
106
110
  unchanged, so short-circuiting and the value of the expression are
@@ -1,8 +1,14 @@
1
1
  module ConditionCoverage
2
2
  # One site's condition as the manifest found it: its operator
3
3
  # and its operands, each the byte range of a leaf or a nested
4
- # Condition.
5
- Condition = Data.define(:operator, :operands) do
4
+ # Condition. A site's commands are the byte ranges of its
5
+ # leaves that are command calls, eg `ok? id`.
6
+ Condition = Data.define(:operator, :operands, :commands) do
7
+ # A condition with no command-call leaves by default.
8
+ def initialize(operator:, operands:, commands: [])
9
+ super
10
+ end
11
+
6
12
  # The byte range of every leaf operand, left to right; a
7
13
  # leaf's index here is the index it is recorded under.
8
14
  def leaves
@@ -1,3 +1,4 @@
1
+ require 'fileutils'
1
2
  require_relative 'configuration'
2
3
  require_relative 'gaps'
3
4
  require_relative 'html_report'
@@ -73,10 +74,12 @@ module ConditionCoverage
73
74
  end
74
75
 
75
76
  # Writes the JSON report, then runs the chosen reporters, for
76
- # every covered file whether or not the run loaded it.
77
+ # every covered file whether or not the run loaded it, into
78
+ # coverage_dir, created first if need be.
77
79
  def self.report(config)
78
80
  files = parsed_files(config)
79
81
  result = Result.new(merged_sites(files), @recorder.counts)
82
+ FileUtils.mkdir_p(config.output_dir)
80
83
  JsonWriter.write(result, config.json_path)
81
84
  run_reporters(result, files, config)
82
85
  end
@@ -19,6 +19,7 @@ module ConditionCoverage
19
19
  def initialize(path)
20
20
  @path = path
21
21
  @sites = {}
22
+ @commands = []
22
23
  super()
23
24
  end
24
25
 
@@ -43,7 +44,11 @@ module ConditionCoverage
43
44
  def add_site(node)
44
45
  site = Site.of(@path, node)
45
46
  @sites[site] = nil
46
- @sites[site] = condition_of(node)
47
+ outer = @commands
48
+ @commands = []
49
+ condition = condition_of(node)
50
+ @sites[site] = condition.with(commands: @commands)
51
+ @commands = outer
47
52
  end
48
53
 
49
54
  # node as a Condition, operands and all, named by its
@@ -72,11 +77,21 @@ module ConditionCoverage
72
77
  end
73
78
 
74
79
  # The byte range of a leaf operand, once any site inside
75
- # it is noted too.
80
+ # it is noted too, and the range among its site's commands
81
+ # if it is a command call.
76
82
  def leaf(operand)
77
83
  operand.accept(self)
78
84
  loc = operand.location
79
- loc.start_offset...loc.end_offset
85
+ range = loc.start_offset...loc.end_offset
86
+ @commands << range if command?(operand)
87
+ range
88
+ end
89
+
90
+ # True for a call to a named method with arguments and no
91
+ # parentheses, eg `id.include? 'N'`, but not `id.size == 6`.
92
+ def command?(node)
93
+ node.type == :call_node && node.arguments &&
94
+ node.opening_loc.nil? && node.name.match?(/\A[a-z_]/i)
80
95
  end
81
96
 
82
97
  # The one statement inside a parenthesised operand, or the
@@ -9,18 +9,21 @@ module ConditionCoverage
9
9
  def self.rewrite(source, sites)
10
10
  inserts = sites.flat_map do |site, condition|
11
11
  condition.leaves.each_with_index.flat_map do |range, index|
12
- wrap(site, index, range)
12
+ command = condition.commands.include?(range)
13
+ wrap(site, index, range, command)
13
14
  end
14
15
  end
15
16
  apply(source.dup, inserts)
16
17
  end
17
18
 
18
- # The two inserts that wrap one operand in a record call.
19
- # The operand gets parentheses of its own, since one such
20
- # as `ok? id` is not valid as a bare argument.
21
- def self.wrap(site, index, range)
22
- call = "ConditionCoverage.record(#{site.inspect}, #{index}, ("
23
- [[range.begin, call], [range.end, '))']]
19
+ # The two inserts that wrap one operand in a record call. A
20
+ # command call is parenthesised, as it is no bare argument;
21
+ # nothing else is, since parentheses make a statement, which
22
+ # gives its line a line-coverage count of its own.
23
+ def self.wrap(site, index, range, command)
24
+ open, close = command ? ['(', '))'] : ['', ')']
25
+ call = "ConditionCoverage.record(#{site.inspect}, #{index}, "
26
+ [[range.begin, call + open], [range.end, close]]
24
27
  end
25
28
 
26
29
  # Splices each [offset, text] insert into source,
@@ -1,3 +1,3 @@
1
1
  module ConditionCoverage
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: condition_coverage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Jagger
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-10-31 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: prism
@@ -26,7 +25,6 @@ dependencies:
26
25
  version: '1.0'
27
26
  description: Records whether each operand of every &&, ||, and and or condition was
28
27
  seen both true and false, and reports the gaps in the terminal and as HTML.
29
- email:
30
28
  executables: []
31
29
  extensions: []
32
30
  extra_rdoc_files: []
@@ -62,7 +60,6 @@ licenses:
62
60
  - BSD-2-Clause
63
61
  metadata:
64
62
  rubygems_mfa_required: 'true'
65
- post_install_message:
66
63
  rdoc_options: []
67
64
  require_paths:
68
65
  - lib
@@ -77,8 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
74
  - !ruby/object:Gem::Version
78
75
  version: '0'
79
76
  requirements: []
80
- rubygems_version: 3.5.22
81
- signing_key:
77
+ rubygems_version: 4.0.23
82
78
  specification_version: 4
83
79
  summary: Condition coverage for Ruby, alongside SimpleCov branch coverage
84
80
  test_files: []