metric_fu 4.1.2 → 4.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.travis.yml +7 -4
  2. data/.yardopts +5 -0
  3. data/CONTRIBUTING.md +28 -13
  4. data/Gemfile +7 -3
  5. data/HISTORY.md +12 -0
  6. data/README.md +17 -0
  7. data/TODO.md +74 -79
  8. data/lib/metric_fu.rb +8 -0
  9. data/lib/metric_fu/configuration.rb +8 -3
  10. data/lib/metric_fu/core_ext.rb +2 -0
  11. data/lib/metric_fu/core_ext/inflector/inflections.rb +214 -0
  12. data/lib/metric_fu/core_ext/inflector/methods.rb +153 -0
  13. data/lib/metric_fu/core_ext/object.rb +3 -0
  14. data/lib/metric_fu/core_ext/object/blank.rb +106 -0
  15. data/lib/metric_fu/core_ext/object/to_json.rb +12 -0
  16. data/lib/metric_fu/core_ext/string.rb +2 -0
  17. data/lib/metric_fu/core_ext/string/inflections.rb +195 -0
  18. data/lib/metric_fu/initial_requires.rb +0 -8
  19. data/lib/metric_fu/metrics/base_template.rb +28 -1
  20. data/lib/metric_fu/metrics/churn/churn.rb +2 -2
  21. data/lib/metric_fu/metrics/churn/template_awesome/churn.html.erb +8 -6
  22. data/lib/metric_fu/metrics/hotspots/analysis/code_issue.rb +6 -0
  23. data/lib/metric_fu/metrics/hotspots/init.rb +1 -0
  24. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +37 -20
  25. data/lib/metric_fu/reporting/templates/awesome/css/bluff.css +15 -0
  26. data/lib/metric_fu/reporting/templates/awesome/css/default.css +0 -48
  27. data/lib/metric_fu/reporting/templates/awesome/css/rcov.css +32 -0
  28. data/lib/metric_fu/reporting/templates/awesome/index.html.erb +4 -32
  29. data/lib/metric_fu/reporting/templates/awesome/layout.html.erb +2 -0
  30. data/lib/metric_fu/version.rb +1 -1
  31. data/metric_fu.gemspec +23 -11
  32. data/spec/cli/helper_spec.rb +38 -28
  33. data/spec/metric_fu/configuration_spec.rb +35 -22
  34. data/spec/metric_fu/metrics/base_template_spec.rb +7 -7
  35. data/spec/metric_fu/metrics/churn/churn_spec.rb +9 -2
  36. data/spec/metric_fu/metrics/flog/flog_spec.rb +57 -55
  37. data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +0 -2
  38. data/spec/run_spec.rb +0 -8
  39. data/spec/support/suite.rb +3 -1
  40. metadata +74 -125
  41. data/home_page/back_all.jpg +0 -0
  42. data/home_page/cc.rb.gif +0 -0
  43. data/home_page/churn.gif +0 -0
  44. data/home_page/cruise_control_1.gif +0 -0
  45. data/home_page/cyclomatic.gif +0 -0
  46. data/home_page/flay.gif +0 -0
  47. data/home_page/flog.gif +0 -0
  48. data/home_page/flog2.gif +0 -0
  49. data/home_page/footer.gif +0 -0
  50. data/home_page/header.jpg +0 -0
  51. data/home_page/hotspot.gif +0 -0
  52. data/home_page/img09.gif +0 -0
  53. data/home_page/index.html +0 -138
  54. data/home_page/rcov.gif +0 -0
  55. data/home_page/reek.gif +0 -0
  56. data/home_page/robots.txt +0 -5
  57. data/home_page/roodi.gif +0 -0
  58. data/home_page/saikuro.gif +0 -0
  59. data/home_page/stats.gif +0 -0
  60. data/home_page/styles.css +0 -245
  61. data/home_page/title.gif +0 -0
  62. data/home_page/title_back.gif +0 -0
  63. data/lib/metric_fu/metrics/cane/template_standard/cane.html.erb +0 -95
  64. data/lib/metric_fu/metrics/churn/template_standard/churn.html.erb +0 -31
  65. data/lib/metric_fu/metrics/flay/template_standard/flay.html.erb +0 -34
  66. data/lib/metric_fu/metrics/flog/template_standard/flog.html.erb +0 -57
  67. data/lib/metric_fu/metrics/hotspots/template_standard/hotspots.html.erb +0 -54
  68. data/lib/metric_fu/metrics/rails_best_practices/template_standard/rails_best_practices.html.erb +0 -29
  69. data/lib/metric_fu/metrics/rcov/template_standard/rcov.html.erb +0 -43
  70. data/lib/metric_fu/metrics/reek/template_standard/reek.html.erb +0 -42
  71. data/lib/metric_fu/metrics/roodi/template_standard/roodi.html.erb +0 -29
  72. data/lib/metric_fu/metrics/saikuro/template_standard/saikuro.html.erb +0 -84
  73. data/lib/metric_fu/metrics/stats/template_standard/stats.html.erb +0 -55
  74. data/lib/metric_fu/reporting/templates/standard/default.css +0 -64
  75. data/lib/metric_fu/reporting/templates/standard/index.html.erb +0 -44
  76. data/lib/metric_fu/reporting/templates/standard/standard_template.rb +0 -26
data/.travis.yml CHANGED
@@ -1,11 +1,14 @@
1
1
  language: ruby
2
+ bundler_args: --without development
3
+ script: bundle exec rspec
4
+ # gemfile:
5
+ # - gemfiles/Gemfile.ci
6
+ # before_install: some_command
7
+ # env:
8
+ # - "rack=1.3.4"
2
9
  rvm:
3
10
  - 2.0.0
4
11
  - 1.9.3
5
12
  - 1.9.2
6
13
  - jruby-19mode # JRuby in 1.9 mode
7
14
  - rbx-19mode
8
- matrix:
9
- allow_failures:
10
- - rvm: jruby-19mode
11
- - rvm: rbx-19mode
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --no-private
2
+ --readme README.md
3
+ lib/metric_fu.rb
4
+ lib/metric_fu_requires.rb
5
+ lib/metric_fu/**/*.rb
data/CONTRIBUTING.md CHANGED
@@ -1,19 +1,34 @@
1
1
  How to contribute:
2
2
 
3
- 1. Fork metric_fu on github.
4
- 2. bundle install
5
- 3. Run the tests ('bundle exec rake')
6
- 4. Run metric_fu on itself ('bundle exec metric_fu -r')
7
- 5. Make the changes you want and back them up with tests.
8
- 6. Make sure two important rake tests still run ('bundle exec rake' and 'bundle exec rake metrics:all')
9
- 7. Commit and send me a pull request with details as to what has been changed.
3
+ ## Bug reports / Issues
10
4
 
11
- Extra Credit:
5
+ * Is something broken or not working as expected? Check for an existing issue or [create a new one](https://github.com/metricfu/metric_fu/issues/new)
6
+ * See [Quick guide to writing good bug reports](https://github.com/metricfu/metric_fu/wiki/Issues:-Quick-guide-to-writing-good-bug-reports)
12
7
 
13
- 1. Make sure your changes work in 1.8.7, Ruby Enterprise Edition, and 1.9.3 (Hint use 'rvm' to help install multiple rubies)
14
- 2. Update the documentation here or the rubyforge web page inside the `'home_page'` folder
15
- 3. Update the History and give yourself credit.
8
+ ## Code
16
9
 
17
- The more of the above steps you do the easier it will be for me to merge in which will greatly increase you chances of getting your changes accepted.
10
+ 1. Clone the repo: `git clone git://github.com/metricfu/metric_fu.git && cd metric_fu`
11
+ 2. Install the gem dependencies: `bundle install`
12
+ 3. Make the changes you want and back them up with tests.
13
+ * Run the tests (`bundle exec rake`)
14
+ * Run metric_fu on itself (`bundle exec rake metrics:all`)
15
+ 4. Update the HISTORY.md file with your changes and give yourself credit
16
+ 5. Commit and create a pull request with details as to what has been changed and why
17
+ * Use well-described, small (atomic) commits.
18
+ * Include links to any relevant github issues.
19
+ * *Don't* change the VERSION file.
20
+ 6. Extra Credit: [Confirm it runs and tests pass on the rubies specified in the travis config](.travis.yml). I will otherwise confirm it runs on these.
18
21
 
19
- Also see [Quick guide to writing good bug reports](https://github.com/metricfu/metric_fu/wiki/Issues:-Quick-guide-to-writing-good-bug-reports)
22
+ How I handle pull requests:
23
+
24
+ * If the tests pass and the pull request looks good, I will merge it.
25
+ * If the pull request needs to be changed,
26
+ * you can change it by updating the branch you generated the pull request from
27
+ * either by adding more commits, or
28
+ * by force pushing to it
29
+ * I can make any changes myself and manually merge the code in.
30
+
31
+ ## Documentation
32
+
33
+ * If relevant, you may update [the metric_fu website](https://github.com/metricfu/metricfu.github.com) in a separate pull request to that repo
34
+ * Update the wiki
data/Gemfile CHANGED
@@ -1,10 +1,14 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rake'
4
- group :development, :test do
4
+ # alternative graphing gem
5
+ gem "googlecharts"
6
+ group :development do
7
+
8
+ end
9
+ group :test do
5
10
  gem "rspec", '>2'
6
- gem "test-construct", ">= 1.2.0"
7
- gem "googlecharts"
11
+ gem 'test-construct'
8
12
  if ENV['COVERAGE']
9
13
  gem 'simplecov'
10
14
  # https://github.com/kina/simplecov-rcov-text
data/HISTORY.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ### Master
2
2
 
3
+ ### MetricFu 4.1.3 / 2013-05-13
4
+
5
+ * Features
6
+ * Tests now pass in JRuby and Rubinius! (Benjamin Fleischer)
7
+ * Fixes
8
+ * Line numbers now display and link properly in annotated code (Benjamin Fleischer)
9
+ * No longer remove historical metrics when testing metric_fu
10
+ * Churn metric handler won't crash when no source control found (Dan Mayer)
11
+ * Misc (Benjamin Fleischer)
12
+ * Removed StandardTemplate, had no additional value and needed to be maintained
13
+ * Removed most template references to specific metrics
14
+
3
15
  ### MetricFu 4.1.2 / 2013-04-17
4
16
 
5
17
  * Fixes
data/README.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # MetricFu [![Gem Version](https://badge.fury.io/rb/metric_fu.png)](http://badge.fury.io/rb/metric_fu) [![Build Status](https://travis-ci.org/metricfu/metric_fu.png?branch=master)](http://travis-ci.org/metricfu/metric_fu) [![Code Climate](https://codeclimate.com/github/metricfu/metric_fu.png)](https://codeclimate.com/github/metricfu/metric_fu) [![Dependency Status](https://gemnasium.com/metricfu/metric_fu.png)](https://gemnasium.com/metricfu/metric_fu)
2
2
 
3
+ ## Metrics
4
+
5
+ * [Cane](https://rubygems.org/gems/cane), [Source](http://github.com/square/cane)
6
+ * [Churn](https://rubygems.org/gems/churn), [Source](http://github.com/danmayer/churn)
7
+ * [Flog](https://rubygems.org/gems/flog), [Source](https://github.com/seattlerb/flog)
8
+ * [Flay](https://rubygems.org/gems/flay), [Source](https://github.com/seattlerb/flay)
9
+ * [Reek](https://rubygems.org/gems/reek) [Source](https://github.com/troessner/reek)
10
+ * [Roodi](https://rubygems.org/gems/metric_fu-roodi), [Source](https://github.com/metricfu/roodi)
11
+ * [Saikuro](https://rubygems.org/gems/japgolly-Saikuro), [Source](https://github.com/japgolly/Saikuro)
12
+ * Rails-only
13
+ * [Rails Best Practices](https://rubygems.org/gems/rails_best_practices), [Source](https://github.com/railsbp/rails_best_practices)
14
+ * Rails `rake stats` task (see [gem](https://rubygems.org/gems/code_statistics), [Source](https://github.com/danmayer/code_statistics) )
15
+ * Test Coverage
16
+ * 1.9: [SimpleCov](http://rubygems.org/gems/simplecov) and [SimpleCov-Rcov-Text](http://rubygems.org/gems/simplecov-rcov-text)
17
+ * 1.8 [Rcov](http://rubygems.org/gems/rcov)
18
+ * Hotspots (a meta-metric of the above)
19
+
3
20
  ## Installation
4
21
 
5
22
  gem install metric_fu
data/TODO.md CHANGED
@@ -2,107 +2,86 @@
2
2
 
3
3
  * Keep HISTORY.md in master up to date
4
4
 
5
- * [Fix jruby/rbx errors on travis](https://travis-ci.org/metricfu/metric_fu)
5
+ Items in each category are in generally order of decreasing priority.
6
+ The categories themselves are not in any priority order.
6
7
 
7
- ## Before next release
8
-
9
- * Move code that references rcov out of
10
-
11
- lib/reporting/templates/awesome/css/default.css
12
- lib/reporting/templates/awesome/index.html.erb
13
- lib/reporting/templates/standard/default.css
14
- lib/reporting/templates/standard/index.html.erb
15
-
16
- * Move code that references flog out of
17
-
18
- lib/configuration.rb
19
- lib/metrics/hotspots/analysis/code_issue.rb
20
- lib/reporting/templates/awesome/index.html.erb
21
- lib/reporting/templates/standard/index.html.erb
22
-
23
- * Move code that references flay out of
24
-
25
- lib/metrics/generator.rb
26
- lib/metrics/hotspots/analysis/code_issue.rb
27
- lib/reporting/templates/awesome/index.html.erb
28
- lib/reporting/templates/standard/index.html.erb
29
-
30
- * Move code that references churn out of
31
-
32
- lib/metrics/hotspots/analysis/code_issue.rb
33
- lib/metrics/hotspots/init.rb
34
- lib/reporting/templates/awesome/index.html.erb
35
- lib/reporting/templates/standard/index.html.erb
36
-
37
- * Move code that references rails_best_practices out of
38
-
39
- lib/metrics/hotspots/analysis/code_issue.rb
40
- lib/reporting/templates/awesome/index.html.erb
41
- lib/reporting/templates/standard/index.html.erb
42
-
43
-
44
- * Move code that references reek out of
45
-
46
- lib/metrics/hotspots/analysis/code_issue.rb
47
- lib/reporting/templates/awesome/index.html.erb
48
- lib/reporting/templates/standard/index.html.erb
49
-
50
-
51
- * Move code that references roodi out of
52
-
53
- lib/metrics/hotspots/analysis/code_issue.rb
54
- lib/reporting/templates/awesome/index.html.erb
55
- lib/reporting/templates/standard/index.html.erb
56
-
57
- * Move code that references saikuro out of
58
-
59
- lib/metrics/hotspots/analysis/code_issue.rb
60
- lib/reporting/templates/awesome/index.html.erb
61
- lib/reporting/templates/standard/index.html.erb
62
-
63
- * Move code that references stats out of
64
-
65
- lib/reporting/templates/awesome/index.html.erb
66
- lib/reporting/templates/standard/index.html.erb
67
-
68
- * Review how metric_fu uses each tools to generate metrics, e.g. by shelling out commands, rake task, modifying the output, etc.
69
-
70
- * Change MetricFu.report.add(metric) to e.g. MetricFu.generate_report(metric) to make clear that this actually runs the tool
71
-
72
- * Allow the coverage task to specify the command it runs plus any flags (see bundler/capistrano options)
73
-
74
- * Test against a rails app
8
+ Also see [CONTRIBUTING](./CONTRIBUTING.md)
75
9
 
76
10
  ## Features
77
11
 
78
- * Look into adding
79
- * https://github.com/metricfu/code_statistics
80
- * brakeman https://github.com/metricfu/brakeman
81
- * laser https://github.com/metricfu/laser
12
+ * Make it easier to whitelist metrics when running from the commanline (cli)
13
+ * Be able to specify folders to run against rather than just app and lib
14
+ * Be able to run metric tools from metric_fu without shelling out
15
+ * Allow the coverage task to specify the command it runs plus any flags (see bundler/capistrano options)
82
16
  * Add configurable logger to all output streams
83
- * Color code flog results with scale from: http://jakescruggs.blogspot.com/2008/08/whats-good-flog-score.html
84
- * Make running metric_fu on metric_fu less embarrassing
85
17
  * Load all gems at config time so you fail fast if one is missing
86
- * Refactor the hotspots code
87
-
18
+ * Color code flog results with scale from: http://jakescruggs.blogspot.com/2008/08/whats-good-flog-score.html
19
+ * Make the template pages prettier (hold off until [61](https://github.com/metricfu/metric_fu/pull/61) is merged)
20
+ * Be able to generate historical metrics for eg gem releases (tagged with appropriate date)
88
21
 
89
22
  ## Testing
90
23
 
24
+ * Test against a rails app, see [yui-rails](https://github.com/nextmat/yui-rails/tree/master/test/dummy)
91
25
  * Determine how to test metric_fu against codebases that are not metric_fu, to ensure it works on most applications
92
26
  * This is especially true for rails applications
93
27
  * Remove / Modify Devver code from the generators/hotspots_spec and base/hotspot_analzyer_spec
28
+ * Add tests
29
+ * Remove useless tests
30
+ * Remove tests that use StandardTemplate. Will require updating tests yml output, which may not be easy
94
31
 
95
32
  ## Bugs / Fixes
96
33
 
34
+ * See issues
35
+
97
36
  ## Misc
98
37
 
38
+ ### Improvements
39
+
40
+ * See TODO items in the code
41
+ * Change how config works to not metaprogrammatically create so many
42
+ instance variables and accessors
43
+ * Clarify the execution path and what a metric's api should be, (repeat for templates and graphs)
44
+ * Change MetricFu.report.add(metric) to e.g. MetricFu.generate_report(metric) to make clear that this actually runs the tool
45
+ * Clarify hotspot weighting
46
+ * Update the wiki with use cases
47
+ * Review how metric_fu uses each tools to generate metrics, e.g. by shelling out commands, rake task, modifying the output, etc.
48
+ * Understand and explain s-expressions and how they're used (or should be ) in [line_numbers.rb](https://github.com/metricfu/metric_fu/blob/master/lib/metric_fu/data_structures/line_numbers.rb) (via the ruby_parser)
49
+ * maybe see [reek tree dresser](https://github.com/troessner/reek/blob/master/lib/reek/source/tree_dresser.rb) and [reek code parser](https://github.com/troessner/reek/blob/master/lib/reek/core/code_parser.rb) or
50
+ * [ripper-tags](https://github.com/tmm1/ripper-tags)
51
+ * Remove dead code
99
52
  * Determine if CodeIssue is used, else remove it
100
53
  * Remove references to Ruport from the Devver / Caliper code
101
- * Update or move the homepage http://metric-fu.rubyforge.org/
54
+ * Understand and explain how each metric can be used
55
+ * Improve metric_fu code metrics
56
+ * Refactor the hotspots code
102
57
  * Is there any reason not to remove the Manifest.txt?
58
+ * Consider removing need for the core extensions (ActiveSupport)
59
+
60
+ ### Documentation
61
+
62
+ * Get the rdoc (or yard) published
63
+ * Add more inline documentation
103
64
  * See other documentation code for examples to improve ours:
104
65
  * https://github.com/charliesome/better_errors/blob/master/CONTRIBUTING.md
105
66
  * https://github.com/charliesome/better_errors/blob/master/README.md
67
+
68
+ ### Other
69
+
70
+ * Look into issues for the tools metric_fu uses
71
+ * Look into other tools that might work well
72
+ * Update contributing or issue guidlines
73
+ * Suggest commit message guidelines
74
+ * [Update the homepage](https://github.com/metricfu/metricfu.github.com)
75
+
76
+ ## Future Thoughts
77
+
78
+ * Look into how to manage plugins or otherwise load abritrary metrics
79
+ * [Hoe](https://github.com/seattlerb/hoe/blob/master/lib/hoe.rb#L301)
80
+ * CLI [Flog](https://github.com/seattlerb/flog/blob/master/lib/flog_cli.rb) Plugins [Flog](https://github.com/seattlerb/flog/blob/master/lib/flog_cli.rb#L34)
81
+ * Look into adding
82
+ * https://github.com/metricfu/code_statistics [1](https://github.com/cloudability/code_statistics)
83
+ * brakeman https://github.com/metricfu/brakeman
84
+ * laser https://github.com/metricfu/laser
106
85
  * Other intersting libraries to consider:
107
86
  * https://gist.github.com/4562865 for generating Flog on ERB templates by jamesmartin
108
87
  * https://github.com/chad/turbulence churn and complexity (flog)
@@ -112,7 +91,23 @@ lib/reporting/templates/standard/index.html.erb
112
91
  * https://github.com/metricfu/gauntlet
113
92
  * https://github.com/metricfu/repodepot-ruby https://twitter.com/jakescruggs/status/70521977303076865
114
93
  * https://github.com/eladmeidar/rails_indexes
115
- * https://github.com/trptcolin/consistency_fail
94
+ * https://github.com/trptcolin/consistency_fail
116
95
  * https://github.com/thoughtbot/appraisal
117
96
  * https://github.com/jenkinsci/rubymetrics-plugin
118
97
  * https://github.com/holman/hopper
98
+ * https://github.com/eric/metriks
99
+
100
+ ## Useful Links
101
+
102
+ ### Ruby Guides
103
+
104
+ * https://github.com/cwgem/RubyGuide
105
+ * https://github.com/bbatsov/rubocop
106
+ * https://github.com/bbatsov/ruby-style-guide
107
+ * https://github.com/bbatsov/rails-style-guide
108
+ * [Learning resources](http://www.benjaminfleischer.com/learning/ruby/tutorials.html) [Source](https://github.com/bf4/learning/tree/gh-pages)
109
+
110
+ ### Perf tools
111
+
112
+ * https://github.com/tmm1/perftools.rb
113
+ * https://twitter.com/mperham/status/311332913641840641
data/lib/metric_fu.rb CHANGED
@@ -41,6 +41,7 @@ module MetricFu
41
41
  (ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu')
42
42
  end
43
43
  def self.configure
44
+ MetricFu.lib_require { 'core_ext' }
44
45
  MetricFu.lib_require { 'configuration' }
45
46
  init_files = Dir.glob(File.join(MetricFu.metrics_dir, '**/init.rb')).reject do |file|
46
47
  if file =~ /rcov/o
@@ -66,6 +67,13 @@ module MetricFu
66
67
  end
67
68
  MetricFu.configuration
68
69
  end
70
+ def self.mri_only_metrics
71
+ if MetricFu.configuration.mri?
72
+ []
73
+ else
74
+ [:cane, :flog, :rails_best_practices]
75
+ end
76
+ end
69
77
  def self.run_rcov
70
78
  load File.join(MetricFu.metrics_dir, 'rcov/init.rb')
71
79
  end
@@ -119,11 +119,11 @@ module MetricFu
119
119
  end
120
120
 
121
121
  def jruby?
122
- @jruby ||= RedCard.check(:jruby)
122
+ @jruby ||= !!RedCard.check(:jruby)
123
123
  end
124
124
 
125
125
  def mri?
126
- @mri ||= RedCard.check(:ruby)
126
+ @mri ||= !!RedCard.check(:ruby)
127
127
  end
128
128
 
129
129
  def platform #:nodoc:
@@ -133,8 +133,13 @@ module MetricFu
133
133
  end
134
134
 
135
135
  def self.ruby_strangely_makes_accessors_private?
136
- RedCard.check('1.9.2') || jruby?
136
+ ruby192? || jruby?
137
137
  end
138
+
139
+ def self.ruby192?
140
+ @ruby192 ||= !!RedCard.check('1.9.2')
141
+ end
142
+
138
143
  protected unless ruby_strangely_makes_accessors_private?
139
144
 
140
145
  def add_promiscuous_instance_variable(name,value)
@@ -0,0 +1,2 @@
1
+ MetricFu.lib_require { 'core_ext/object' }
2
+ MetricFu.lib_require { 'core_ext/string' }
@@ -0,0 +1,214 @@
1
+ # https://raw.github.com/rails/rails/20768176292cbcb883ab152b4aa9ed8c664771cd/activesupport/lib/active_support/inflector/inflections.rb
2
+ # not https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/inflector/inflections.rb
3
+ MetricFu.lib_require { 'core_ext/inflector/methods' }
4
+ module ActiveSupport
5
+ module Inflector
6
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
7
+ # inflection rules. Examples:
8
+ #
9
+ # ActiveSupport::Inflector.inflections do |inflect|
10
+ # inflect.plural /^(ox)$/i, '\1\2en'
11
+ # inflect.singular /^(ox)en/i, '\1'
12
+ #
13
+ # inflect.irregular 'octopus', 'octopi'
14
+ #
15
+ # inflect.uncountable "equipment"
16
+ # end
17
+ #
18
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
19
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
20
+ # already have been loaded.
21
+ class Inflections
22
+ def self.instance
23
+ @__instance__ ||= new
24
+ end
25
+
26
+ attr_reader :plurals, :singulars, :uncountables, :humans
27
+
28
+ def initialize
29
+ @plurals, @singulars, @uncountables, @humans = [], [], [], []
30
+ end
31
+
32
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
33
+ # The replacement should always be a string that may include references to the matched data from the rule.
34
+ def plural(rule, replacement)
35
+ @uncountables.delete(rule) if rule.is_a?(String)
36
+ @uncountables.delete(replacement)
37
+ @plurals.insert(0, [rule, replacement])
38
+ end
39
+
40
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
41
+ # The replacement should always be a string that may include references to the matched data from the rule.
42
+ def singular(rule, replacement)
43
+ @uncountables.delete(rule) if rule.is_a?(String)
44
+ @uncountables.delete(replacement)
45
+ @singulars.insert(0, [rule, replacement])
46
+ end
47
+
48
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
49
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
50
+ #
51
+ # Examples:
52
+ # irregular 'octopus', 'octopi'
53
+ # irregular 'person', 'people'
54
+ def irregular(singular, plural)
55
+ @uncountables.delete(singular)
56
+ @uncountables.delete(plural)
57
+ if singular[0,1].upcase == plural[0,1].upcase
58
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
59
+ plural(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + plural[1..-1])
60
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
61
+ else
62
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
63
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
64
+ plural(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
65
+ plural(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
66
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
67
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
68
+ end
69
+ end
70
+
71
+ # Add uncountable words that shouldn't be attempted inflected.
72
+ #
73
+ # Examples:
74
+ # uncountable "money"
75
+ # uncountable "money", "information"
76
+ # uncountable %w( money information rice )
77
+ def uncountable(*words)
78
+ (@uncountables << words).flatten!
79
+ end
80
+
81
+ # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
82
+ # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
83
+ # When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
84
+ #
85
+ # Examples:
86
+ # human /_cnt$/i, '\1_count'
87
+ # human "legacy_col_person_name", "Name"
88
+ def human(rule, replacement)
89
+ @humans.insert(0, [rule, replacement])
90
+ end
91
+
92
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
93
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
94
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
95
+ #
96
+ # Examples:
97
+ # clear :all
98
+ # clear :plurals
99
+ def clear(scope = :all)
100
+ case scope
101
+ when :all
102
+ @plurals, @singulars, @uncountables = [], [], []
103
+ else
104
+ instance_variable_set "@#{scope}", []
105
+ end
106
+ end
107
+ end
108
+
109
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
110
+ # inflector rules.
111
+ #
112
+ # Example:
113
+ # ActiveSupport::Inflector.inflections do |inflect|
114
+ # inflect.uncountable "rails"
115
+ # end
116
+ def inflections
117
+ if block_given?
118
+ yield Inflections.instance
119
+ else
120
+ Inflections.instance
121
+ end
122
+ end
123
+
124
+ # Returns the plural form of the word in the string.
125
+ #
126
+ # Examples:
127
+ # "post".pluralize # => "posts"
128
+ # "octopus".pluralize # => "octopi"
129
+ # "sheep".pluralize # => "sheep"
130
+ # "words".pluralize # => "words"
131
+ # "CamelOctopus".pluralize # => "CamelOctopi"
132
+ def pluralize(word)
133
+ result = word.to_s.dup
134
+
135
+ if word.empty? || inflections.uncountables.include?(result.downcase)
136
+ result
137
+ else
138
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
139
+ result
140
+ end
141
+ end
142
+
143
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
144
+ #
145
+ # Examples:
146
+ # "posts".singularize # => "post"
147
+ # "octopi".singularize # => "octopus"
148
+ # "sheep".singularize # => "sheep"
149
+ # "word".singularize # => "word"
150
+ # "CamelOctopi".singularize # => "CamelOctopus"
151
+ def singularize(word)
152
+ result = word.to_s.dup
153
+
154
+ if inflections.uncountables.any? { |inflection| result =~ /\b(#{inflection})\Z/i }
155
+ result
156
+ else
157
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
158
+ result
159
+ end
160
+ end
161
+
162
+ # Capitalizes the first word and turns underscores into spaces and strips a
163
+ # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
164
+ #
165
+ # Examples:
166
+ # "employee_salary" # => "Employee salary"
167
+ # "author_id" # => "Author"
168
+ def humanize(lower_case_and_underscored_word)
169
+ result = lower_case_and_underscored_word.to_s.dup
170
+
171
+ inflections.humans.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
172
+ result.gsub(/_id$/, "").gsub(/_/, " ").capitalize
173
+ end
174
+
175
+ # Capitalizes all the words and replaces some characters in the string to create
176
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
177
+ # used in the Rails internals.
178
+ #
179
+ # +titleize+ is also aliased as as +titlecase+.
180
+ #
181
+ # Examples:
182
+ # "man from the boondocks".titleize # => "Man From The Boondocks"
183
+ # "x-men: the last stand".titleize # => "X Men: The Last Stand"
184
+ def titleize(word)
185
+ humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
186
+ end
187
+
188
+ # Create the name of a table like Rails does for models to table names. This method
189
+ # uses the +pluralize+ method on the last word in the string.
190
+ #
191
+ # Examples
192
+ # "RawScaledScorer".tableize # => "raw_scaled_scorers"
193
+ # "egg_and_ham".tableize # => "egg_and_hams"
194
+ # "fancyCategory".tableize # => "fancy_categories"
195
+ def tableize(class_name)
196
+ pluralize(underscore(class_name))
197
+ end
198
+
199
+ # Create a class name from a plural table name like Rails does for table names to models.
200
+ # Note that this returns a string and not a Class. (To convert to an actual class
201
+ # follow +classify+ with +constantize+.)
202
+ #
203
+ # Examples:
204
+ # "egg_and_hams".classify # => "EggAndHam"
205
+ # "posts".classify # => "Post"
206
+ #
207
+ # Singular names are not handled correctly:
208
+ # "business".classify # => "Busines"
209
+ def classify(table_name)
210
+ # strip out any leading schema name
211
+ camelize(singularize(table_name.to_s.sub(/.*\./, '')))
212
+ end
213
+ end
214
+ end