turbulence 1.2.3 → 1.3.0

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
- SHA1:
3
- metadata.gz: 9ddbf7b10c94cfd01747886dd397fa075fcc7dff
4
- data.tar.gz: b93662fd01158ed29fcc2b9d308a8224582a91d1
2
+ SHA256:
3
+ metadata.gz: a2023fddd852d412e27f0a4daab0755c0e30bc611ac27656f9a2c2a0a8b20ace
4
+ data.tar.gz: 94460572613993d657687a63a62a367c8c3365aafde2cf6e702cef55d20b4cd1
5
5
  SHA512:
6
- metadata.gz: 1a3a2ba43cfb5fec98e4f99bea0408ad764d23bb00c77bda2684f58e0dcb5566cedaaab7154a433da560ba8613bdcb80210e4a6472376cd47d465da0f1e07022
7
- data.tar.gz: f822adff77f5400bbbb9a7d86c8fe8319afd2d0d632b081f842addc18f42a8123d3cf87f5ab1fd8974056a755a16713be35d28a777d4087ad59cc270d8c856c8
6
+ metadata.gz: a12aacc43132911890a7b4af5129c09bc89cf95399e1f21387da40207be20efbb97a8234d479a884792fcbacf873049be4188d4593fcb57d607f9c0c164cd3ce
7
+ data.tar.gz: 6d29af820ff2e2bcc533b69e78453c856956c3e83f2448dee95a55ea0bd2608015ec2f97f458735a06552b41af9acb666bc563cdf9f2d439d2970ef91e9b702b
@@ -0,0 +1,51 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby-version:
17
+ - '3.0'
18
+ - '3.1'
19
+ - '3.2'
20
+ - '3.3'
21
+ - 'head'
22
+
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - name: Remove Gemfile.lock for fresh resolution
27
+ run: rm -f Gemfile.lock
28
+
29
+ - name: Set up Ruby ${{ matrix.ruby-version }}
30
+ uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: true
34
+
35
+ - name: Run tests
36
+ run: bundle exec rspec
37
+
38
+ lint:
39
+ runs-on: ubuntu-latest
40
+
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+
44
+ - name: Set up Ruby
45
+ uses: ruby/setup-ruby@v1
46
+ with:
47
+ ruby-version: '3.3'
48
+ bundler-cache: true
49
+
50
+ - name: Check gemspec
51
+ run: gem build turbulence.gemspec
data/CHANGELOG.md ADDED
@@ -0,0 +1,208 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.3.0] - 2026-06-13
11
+
12
+ ### Added
13
+ - `--output DIR` option to specify custom output directory for reports ([#39])
14
+ - `--no-open` flag to skip automatic browser launch, useful for CI/headless environments ([#42])
15
+ - GitHub Actions CI testing Ruby 3.0, 3.1, 3.2, 3.3, and head ([#52])
16
+ - CI status badge and RubyGems version badge in README ([#52])
17
+ - LICENSE.txt file (MIT License)
18
+ - Screenshots of scatter plot and treemap visualizations in README ([#58])
19
+
20
+ ### Changed
21
+ - **Ruby 3.0+ / Ruby 4.0 compatibility** ([#50])
22
+ - Update minimum Ruby version to 3.0
23
+ - Add `racc` as runtime dependency (removed from stdlib in Ruby 3.3+)
24
+ - Remove obsolete `Ruby19Parser`/`Flog19` workaround classes
25
+ - Remove unused `ostruct` require
26
+ - Fix git repo detection with case-insensitive regex
27
+ - Update RSpec from 2.x to 3.x and modernize all specs ([#50])
28
+ - Modernize README with table format, examples, and requirements ([#56])
29
+ - Drop defunct `rubyforge_project` property from gemspec ([#46])
30
+ - Update referenced URL in gemspec description ([#44])
31
+ - Use symbols instead of class names as metrics_hash keys ([#34])
32
+
33
+ ### Removed
34
+ - Travis CI configuration (replaced by GitHub Actions) ([#56])
35
+
36
+ ### Fixed
37
+ - Fix typo: "cummulative" → "cumulative" ([#54])
38
+
39
+ ## [1.2.4] - 2014-10-15
40
+
41
+ ### Fixed
42
+ - Fix missing stats bug where metrics hash keys were inconsistent ([#33])
43
+ - Fix missing file bug by creating Calculator::Churn instance to access config ([#32])
44
+
45
+ ### Changed
46
+ - Major refactoring to extract configuration into dedicated class ([#27])
47
+ - Use instances instead of classes for calculators
48
+ - Move CLI option parsing to separate file
49
+ - Improved code organization and reduced complexity
50
+
51
+ ## [1.2.3] - 2014-09-22
52
+
53
+ ### Fixed
54
+ - Revert autogenerated bin changes that caused "stack level too deep" errors for many users ([#30], [#29])
55
+
56
+ ## [1.2.2] - 2014-09-18
57
+
58
+ ### Fixed
59
+ - Fix leaky specs by stubbing ENV settings ([#26])
60
+ - Remove deprecation notices
61
+
62
+ ### Changed
63
+ - Update RSpec dependency
64
+ - Inject output to CLI for cleaner spec output ([#24])
65
+
66
+ ## [1.2.0] - 2014-03-15
67
+
68
+ ### Fixed
69
+ - Fix file opening on Windows by using `file:///` protocol ([#21])
70
+
71
+ ### Added
72
+ - Treemap visualization option (`--treemap` flag) ([#18])
73
+ - Generator classes for scatter plot and treemap visualizations
74
+
75
+ ### Changed
76
+ - Move scatter plot code into dedicated generator class
77
+ - Update flog and launchy gem versions
78
+
79
+ ## [1.1.0] - 2013-08-20
80
+
81
+ ### Fixed
82
+ - Fix parsing of Ruby 1.9 style hashes ([#14])
83
+ - Fix syntax errors under Ruby 1.8.7-352 ([#16])
84
+
85
+ ### Added
86
+ - Additional standard Rails folders for file filtering
87
+ - Support for both Ruby 1.8 and 1.9 syntax
88
+
89
+ ### Changed
90
+ - Update gem dependencies
91
+
92
+ ## [1.0.0] - 2013-03-10
93
+
94
+ ### Added
95
+ - Perforce SCM support with `--scm p4` option ([#11])
96
+ - `--exclude` feature to filter out files matching a pattern ([#13])
97
+ - Commit range option (`--churn-range`) for analyzing specific ranges
98
+ - Mean churn calculation option (`--churn-mean`)
99
+
100
+ ### Changed
101
+ - Extract Git-specific code to separate SCM class
102
+ - Use .gemspec for gem dependencies
103
+ - Upgrade to latest Launchy
104
+ - Allow use of more recent json gems ([#12])
105
+
106
+ ### Fixed
107
+ - Reduced code complexity through refactoring
108
+
109
+ ## [0.0.9] - 2012-11-15
110
+
111
+ ### Changed
112
+ - Refactored metrics loop and output display
113
+ - Move complexity calculation into Calculator::Complexity
114
+ - Move churn work into Calculators::Churn
115
+ - Created CLI class for better organization
116
+
117
+ ### Fixed
118
+ - Bug in churn calculation
119
+ - Filter files to Rails directories
120
+
121
+ ## [0.0.8] - 2012-10-20
122
+
123
+ ### Added
124
+ - Name mangler for anonymization of file names
125
+ - Command line options support
126
+
127
+ ### Changed
128
+ - Lines changed instead of commits for churn metric
129
+ - Total flog score instead of average
130
+ - General code cleanup and refactoring
131
+
132
+ ## [0.0.6] - 2012-09-15
133
+
134
+ ### Added
135
+ - Filename to graph tooltip
136
+ - Churn and complexity to tooltip
137
+
138
+ ### Fixed
139
+ - Exclude nonexistent files from analysis
140
+
141
+ ## [0.0.5] - 2012-08-20
142
+
143
+ ### Added
144
+ - Highcharts integration for visualization
145
+ - Separate series by directory (up to two levels)
146
+
147
+ ### Changed
148
+ - Renamed project from "chuggle" to "turbulence"
149
+
150
+ ## [0.0.4] - 2012-07-15
151
+
152
+ ### Added
153
+ - Basic graphing functionality
154
+ - Gemfile and gemspec
155
+
156
+ ## [0.0.3] - 2012-06-20
157
+
158
+ ### Added
159
+ - Initial working version
160
+ - Churn and flog scoring
161
+ - Basic command line interface
162
+
163
+ ## [0.0.2] - 2012-06-10
164
+
165
+ ### Added
166
+ - Initial gem structure
167
+ - README with basic documentation
168
+
169
+ [Unreleased]: https://github.com/chad/turbulence/compare/1.2.4...HEAD
170
+ [1.3.0]: https://github.com/chad/turbulence/compare/1.2.4...1.3.0
171
+ [1.2.4]: https://github.com/chad/turbulence/compare/1.2.3...1.2.4
172
+ [1.2.3]: https://github.com/chad/turbulence/compare/1.2.2...1.2.3
173
+ [1.2.2]: https://github.com/chad/turbulence/compare/1.2.0...1.2.2
174
+ [1.2.0]: https://github.com/chad/turbulence/compare/1.1.0...1.2.0
175
+ [1.1.0]: https://github.com/chad/turbulence/compare/v1.0.0...1.1.0
176
+ [1.0.0]: https://github.com/chad/turbulence/compare/0.0.9...v1.0.0
177
+ [0.0.9]: https://github.com/chad/turbulence/compare/0.0.8...0.0.9
178
+ [0.0.8]: https://github.com/chad/turbulence/compare/0.0.6...0.0.8
179
+ [0.0.6]: https://github.com/chad/turbulence/compare/0.0.5...0.0.6
180
+ [0.0.5]: https://github.com/chad/turbulence/compare/0.0.4...0.0.5
181
+ [0.0.4]: https://github.com/chad/turbulence/compare/0.0.3...0.0.4
182
+ [0.0.3]: https://github.com/chad/turbulence/compare/0.0.2...0.0.3
183
+ [0.0.2]: https://github.com/chad/turbulence/releases/tag/0.0.2
184
+
185
+ [#58]: https://github.com/chad/turbulence/pull/58
186
+ [#56]: https://github.com/chad/turbulence/pull/56
187
+ [#54]: https://github.com/chad/turbulence/pull/54
188
+ [#52]: https://github.com/chad/turbulence/pull/52
189
+ [#50]: https://github.com/chad/turbulence/pull/50
190
+ [#46]: https://github.com/chad/turbulence/pull/46
191
+ [#44]: https://github.com/chad/turbulence/pull/44
192
+ [#42]: https://github.com/chad/turbulence/issues/42
193
+ [#39]: https://github.com/chad/turbulence/issues/39
194
+ [#34]: https://github.com/chad/turbulence/pull/34
195
+ [#33]: https://github.com/chad/turbulence/pull/33
196
+ [#32]: https://github.com/chad/turbulence/pull/32
197
+ [#30]: https://github.com/chad/turbulence/pull/30
198
+ [#29]: https://github.com/chad/turbulence/issues/29
199
+ [#27]: https://github.com/chad/turbulence/pull/27
200
+ [#26]: https://github.com/chad/turbulence/pull/26
201
+ [#24]: https://github.com/chad/turbulence/pull/24
202
+ [#21]: https://github.com/chad/turbulence/pull/21
203
+ [#18]: https://github.com/chad/turbulence/pull/18
204
+ [#16]: https://github.com/chad/turbulence/pull/16
205
+ [#14]: https://github.com/chad/turbulence/pull/14
206
+ [#13]: https://github.com/chad/turbulence/pull/13
207
+ [#12]: https://github.com/chad/turbulence/pull/12
208
+ [#11]: https://github.com/chad/turbulence/pull/11
data/Gemfile.lock CHANGED
@@ -1,39 +1,62 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- turbulence (1.2.3)
5
- flog (~> 4.1)
6
- json (>= 1.4.6)
4
+ turbulence (1.3.0)
5
+ flog (>= 4.1)
6
+ json
7
7
  launchy (>= 2.0.0)
8
+ racc
8
9
 
9
10
  GEM
10
11
  remote: http://rubygems.org/
11
12
  specs:
12
- addressable (2.3.5)
13
- diff-lcs (1.2.5)
14
- flog (4.1.2)
15
- ruby_parser (~> 3.1, > 3.1.0)
16
- sexp_processor (~> 4.0)
17
- json (1.8.1)
18
- launchy (2.4.2)
19
- addressable (~> 2.3)
20
- rake (10.1.0)
21
- rspec (2.14.1)
22
- rspec-core (~> 2.14.0)
23
- rspec-expectations (~> 2.14.0)
24
- rspec-mocks (~> 2.14.0)
25
- rspec-core (2.14.7)
26
- rspec-expectations (2.14.4)
27
- diff-lcs (>= 1.1.3, < 2.0)
28
- rspec-mocks (2.14.4)
29
- ruby_parser (3.2.2)
30
- sexp_processor (~> 4.1)
31
- sexp_processor (4.4.0)
13
+ addressable (2.9.0)
14
+ public_suffix (>= 2.0.2, < 8.0)
15
+ childprocess (5.1.0)
16
+ logger (~> 1.5)
17
+ diff-lcs (1.6.2)
18
+ flog (4.9.4)
19
+ path_expander (~> 2.0)
20
+ prism (~> 1.7)
21
+ sexp_processor (~> 4.8)
22
+ json (2.19.9)
23
+ launchy (3.1.1)
24
+ addressable (~> 2.8)
25
+ childprocess (~> 5.0)
26
+ logger (~> 1.6)
27
+ logger (1.7.0)
28
+ path_expander (2.0.1)
29
+ prism (1.9.0)
30
+ public_suffix (7.0.5)
31
+ racc (1.8.1)
32
+ rake (13.4.2)
33
+ rspec (3.13.2)
34
+ rspec-core (~> 3.13.0)
35
+ rspec-expectations (~> 3.13.0)
36
+ rspec-mocks (~> 3.13.0)
37
+ rspec-core (3.13.6)
38
+ rspec-support (~> 3.13.0)
39
+ rspec-expectations (3.13.5)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.13.0)
42
+ rspec-its (2.0.0)
43
+ rspec-core (>= 3.13.0)
44
+ rspec-expectations (>= 3.13.0)
45
+ rspec-mocks (3.13.8)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.13.0)
48
+ rspec-support (3.13.7)
49
+ sexp_processor (4.17.5)
32
50
 
33
51
  PLATFORMS
52
+ arm64-darwin-25
34
53
  ruby
35
54
 
36
55
  DEPENDENCIES
37
56
  rake
38
- rspec (~> 2.14.0)
57
+ rspec (~> 3.0)
58
+ rspec-its
39
59
  turbulence!
60
+
61
+ BUNDLED WITH
62
+ 4.0.13
data/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2012-2026 Kerri Miller, Chad Fowler
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,48 +1,117 @@
1
- Hopefully-meaningful Metrics
2
- ============================
1
+ # Turbulence
3
2
 
4
- Based on Michael Feathers' [recent work](http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=16679&tth=DYN&tt=siteemail&iDyn=2) in project churn and complexity.
3
+ [![CI](https://github.com/chad/turbulence/actions/workflows/ci.yml/badge.svg)](https://github.com/chad/turbulence/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/turbulence.svg)](https://badge.fury.io/rb/turbulence)
5
5
 
6
- Here is how to read the graph (extracted from the above article):
6
+ Turbulence visualizes churn vs complexity for your Ruby codebase, helping you identify files that are both highly complex and frequently changed - prime candidates for refactoring.
7
7
 
8
- * The upper right quadrant is particularly important.
9
- These files have a high degree of complexity, and they change quite frequently.
10
- There are a number of reasons why this can happen.
11
- The one to look out for, though, is something I call runaway conditionals.
12
- Sometimes a class becomes so complex that refactoring seems too difficult.
13
- Developers hack if-then-elses into if-then-elses, and the rat’s nest grows. These classes are particularly ripe for a refactoring investment.
8
+ Based on Michael Feathers' work on [getting empirical about refactoring](https://www.stickyminds.com/article/getting-empirical-about-refactoring).
14
9
 
15
- * The lower left quadrant. is the healthy closure region.
16
- Abstractions here have low complexity and don't change much.
10
+ ## Screenshots
17
11
 
18
- * The upper left is what I call the cowboy region. This is complex code that sprang from someone's head and didn't seem to grow incrementally.
12
+ ### Scatter Plot (default)
19
13
 
20
- * The bottom right is very interesting. I call it the fertile ground.
21
- It can consist of files that are somewhat configurational, but often there are also files that act as incubators for new abstractions.
22
- People add code, it grows, and then they factor outward, extracting new classes. The files churn frequently, but their complexity remains low.
14
+ ![Scatter Plot](docs/scatter-plot.png)
23
15
 
16
+ ### Treemap
24
17
 
25
- Installation
26
- ------------
18
+ ![Treemap](docs/treemap.png)
27
19
 
28
- $ gem install turbulence
20
+ ## How to Read the Graph
21
+
22
+ The scatter plot places each file according to its **churn** (x-axis) and **complexity** (y-axis):
23
+
24
+ | Quadrant | Location | What it means |
25
+ |----------|----------|---------------|
26
+ | **Danger Zone** | Upper right | High complexity + high churn. These files change often and are hard to work with. Prime refactoring candidates! |
27
+ | **Healthy Closure** | Lower left | Low complexity + low churn. Stable, well-factored code. Leave it alone. |
28
+ | **Cowboy Code** | Upper left | High complexity + low churn. Complex code that sprang from someone's head fully formed. May need attention if it starts changing. |
29
+ | **Fertile Ground** | Lower right | Low complexity + high churn. Often configuration or incubators for new abstractions. Code grows here, then gets extracted. |
30
+
31
+ ## Requirements
32
+
33
+ - Ruby 3.0 or later
34
+ - Git or Perforce
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ gem install turbulence
40
+ ```
41
+
42
+ ## Usage
29
43
 
30
- Usage
31
- -----
32
44
  In your project directory, run:
33
45
 
34
- $ bule
46
+ ```bash
47
+ bule
48
+ ```
49
+
50
+ This generates and opens `turbulence/turbulence.html` with an interactive scatter plot.
51
+
52
+ ### Options
53
+
54
+ ```bash
55
+ bule [options] [directory]
56
+
57
+ Options:
58
+ --scm p4|git SCM to use (default: git)
59
+ --churn-range A..B Commit range to compute file churn
60
+ --churn-mean Calculate mean churn instead of cumulative
61
+ --exclude PATTERN Exclude files matching pattern
62
+ --treemap Output treemap graph instead of scatter plot
63
+ --no-open Skip opening the report in a browser
64
+ --output DIR Output directory for reports (default: ./turbulence)
65
+ ```
66
+
67
+ ### Examples
68
+
69
+ ```bash
70
+ # Analyze current directory
71
+ bule
72
+
73
+ # Analyze a specific directory
74
+ bule path/to/project
75
+
76
+ # Use Perforce instead of Git
77
+ bule --scm p4
78
+
79
+ # Analyze only recent changes
80
+ bule --churn-range HEAD~100..HEAD
81
+
82
+ # Generate report without opening browser (useful for CI)
83
+ bule --no-open
84
+
85
+ # Output to a custom directory
86
+ bule --output spec/reports/turbulence
87
+
88
+ # Exclude test files
89
+ bule --exclude spec
90
+ ```
91
+
92
+ ### Perforce Support
93
+
94
+ For Perforce, set the `P4CLIENT` environment variable to your client workspace name:
95
+
96
+ ```bash
97
+ export P4CLIENT=my-workspace
98
+ bule --scm p4
99
+ ```
100
+
101
+ ## Privacy Warning
102
+
103
+ Turbulence generates a JavaScript file containing your file paths and names. If these are sensitive, be careful where you put the generated files and who you share them with.
104
+
105
+ ## Contributing
35
106
 
36
- and it will generate (and open) turbulence/turbulence.html
107
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/chad/turbulence).
37
108
 
38
- Supported SCM systems
39
- ---------------------
40
- Currently, bule defaults to using git. If you are using Perforce, call it like so:
109
+ ## License
41
110
 
42
- $ bule --scm p4
111
+ [MIT License](LICENSE.txt)
43
112
 
44
- You need to have an environment variable P4CLIENT set to the name of your client workspace.
113
+ ## Authors
45
114
 
46
- WARNING
47
- -------
48
- When you run bule, it creates a JavaScript file which contains your file paths and names. If those are sensitive, be careful where you put these generated files and who you share them with.
115
+ - [Chad Fowler](https://github.com/chad)
116
+ - [Michael Feathers](https://github.com/michaelfeathers)
117
+ - [Corey Haines](https://github.com/coreyhaines)
data/bin/bule CHANGED
@@ -11,4 +11,4 @@ unless Turbulence::ChecksEnvironment.scm_repo?(Dir.pwd)
11
11
  end
12
12
 
13
13
  cli.generate_bundle
14
- cli.open_bundle
14
+ cli.open_bundle unless cli.no_open
Binary file
data/docs/treemap.png ADDED
Binary file
@@ -1,55 +1,67 @@
1
+ require 'forwardable'
2
+
1
3
  class Turbulence
2
4
  module Calculators
3
5
  class Churn
4
6
  RUBY_FILE_EXTENSION = ".rb"
5
7
 
6
- class << self
7
- attr_accessor :scm, :compute_mean, :commit_range
8
+ attr_reader :config, :type
8
9
 
9
- def for_these_files(files)
10
- changes_by_ruby_file.each do |filename, count|
11
- yield filename, count if files.include?(filename)
12
- end
13
- end
10
+ def initialize(config = nil)
11
+ @config = config || Turbulence.config
12
+ @type = :churn
13
+ end
14
14
 
15
- def changes_by_ruby_file
16
- ruby_files_changed_in_scm.group_by(&:first).map do |filename, stats|
17
- churn_for_file(filename,stats)
18
- end
19
- end
15
+ extend Forwardable
16
+ def_delegators :config, *[
17
+ :scm, :scm=,
18
+ :commit_range, :commit_range=,
19
+ :compute_mean, :compute_mean=,
20
+ ]
20
21
 
21
- def churn_for_file(filename,stats)
22
- churn = stats[0..-2].map(&:last).inject(0){|running_total, changes| running_total + changes}
23
- churn = calculate_mean_of_churn(churn, stats.size - 1) if compute_mean
24
- [filename, churn]
22
+ def for_these_files(files)
23
+ changes_by_ruby_file.each do |filename, count|
24
+ yield filename, count if files.include?(filename)
25
25
  end
26
+ end
26
27
 
27
- def calculate_mean_of_churn(churn, sample_size)
28
- return churn if sample_size < 1
29
- churn /= sample_size
28
+ def changes_by_ruby_file
29
+ ruby_files_changed_in_scm.group_by(&:first).map do |filename, stats|
30
+ churn_for_file(filename,stats)
30
31
  end
32
+ end
31
33
 
32
- def ruby_files_changed_in_scm
33
- counted_line_changes_by_file_by_commit.select do |filename, _|
34
- filename.end_with?(RUBY_FILE_EXTENSION) && File.exist?(filename)
35
- end
36
- end
34
+ def churn_for_file(filename,stats)
35
+ churn = stats[0..-2].map(&:last).inject(0){|running_total, changes| running_total + changes}
36
+ churn = calculate_mean_of_churn(churn, stats.size - 1) if compute_mean
37
+ [filename, churn]
38
+ end
37
39
 
38
- def counted_line_changes_by_file_by_commit
39
- scm_log_file_lines.map do |line|
40
- adds, deletes, filename = line.split(/\t/)
41
- [filename, adds.to_i + deletes.to_i]
42
- end
43
- end
40
+ def calculate_mean_of_churn(churn, sample_size)
41
+ return churn if sample_size < 1
42
+ churn /= sample_size
43
+ end
44
44
 
45
- def scm_log_file_lines
46
- scm_log_command.each_line.reject{|line| line == "\n"}.map(&:chomp)
45
+ def ruby_files_changed_in_scm
46
+ counted_line_changes_by_file_by_commit.select do |filename, _|
47
+ filename.end_with?(RUBY_FILE_EXTENSION) && File.exist?(filename)
47
48
  end
49
+ end
48
50
 
49
- def scm_log_command
50
- scm.log_command(commit_range)
51
+ def counted_line_changes_by_file_by_commit
52
+ scm_log_file_lines.map do |line|
53
+ adds, deletes, filename = line.split(/\t/)
54
+ [filename, adds.to_i + deletes.to_i]
51
55
  end
52
56
  end
57
+
58
+ def scm_log_file_lines
59
+ scm_log_command.each_line.reject{|line| line == "\n"}.map(&:chomp)
60
+ end
61
+
62
+ def scm_log_command
63
+ scm.log_command(commit_range)
64
+ end
53
65
  end
54
66
  end
55
67
  end