metric_fu 4.2.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/HISTORY.md +8 -0
  2. data/checksum/metric_fu-4.2.1.gem.sha512 +1 -0
  3. data/lib/metric_fu.rb +0 -1
  4. data/lib/metric_fu/cli/helper.rb +1 -1
  5. data/lib/metric_fu/data_structures/line_numbers.rb +6 -9
  6. data/lib/metric_fu/initial_requires.rb +1 -0
  7. data/lib/metric_fu/logging/mf_debugger.rb +20 -10
  8. data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +1 -1
  9. data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +1 -1
  10. data/lib/metric_fu/metrics/flog/flog.rb +2 -3
  11. data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +1 -1
  12. data/lib/metric_fu/metrics/graph.rb +2 -2
  13. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +1 -1
  14. data/lib/metric_fu/metrics/rcov/rcov.rb +2 -2
  15. data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +1 -1
  16. data/lib/metric_fu/metrics/reek/reek.rb +1 -1
  17. data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +1 -1
  18. data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +1 -1
  19. data/lib/metric_fu/metrics/saikuro/saikuro.rb +28 -4
  20. data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +1 -1
  21. data/lib/metric_fu/reporting/graphs/engines/gchart.rb +1 -1
  22. data/lib/metric_fu/run.rb +5 -2
  23. data/lib/metric_fu/version.rb +1 -1
  24. data/metric_fu.gemspec +2 -0
  25. data/spec/metric_fu/metrics/flog/flog_spec.rb +1 -1
  26. data/spec/metric_fu/metrics/graph_spec.rb +4 -4
  27. data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +5 -4
  28. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +2 -2
  29. data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +1 -1
  30. metadata +19 -10
  31. data/lib/metric_fu/core_ext.rb +0 -2
  32. data/lib/metric_fu/core_ext/inflector/inflections.rb +0 -214
  33. data/lib/metric_fu/core_ext/inflector/methods.rb +0 -153
  34. data/lib/metric_fu/core_ext/object.rb +0 -3
  35. data/lib/metric_fu/core_ext/object/blank.rb +0 -106
  36. data/lib/metric_fu/core_ext/object/to_json.rb +0 -12
  37. data/lib/metric_fu/core_ext/string.rb +0 -2
  38. data/lib/metric_fu/core_ext/string/inflections.rb +0 -195
data/HISTORY.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ### Master
2
2
 
3
+ ### MetricFu 4.2.1 / 2013-05-23
4
+
5
+ * Fixes
6
+ * Remove ActiveSupport dependencies (Benjamin Fleischer #79)
7
+ * Add MultiJson to ensure JSON support in rbx and jruby (Benjamin Fleischer)
8
+ * Misc
9
+ * Improve STDOUT to show which metric is running but hide the details by default
10
+
3
11
  ### MetricFu 4.2.0 / 2013-05-20
4
12
 
5
13
  * Features
@@ -0,0 +1 @@
1
+ 529b99cf3f5fb314e9a7684ad38198e7509ec13926ded779bfef2a4b968b0538fc72248606a3b0b1bdead31163e04641bd6f565d5db62bb168ee80b854e9c580
@@ -41,7 +41,6 @@ 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' }
45
44
  MetricFu.lib_require { 'configuration' }
46
45
  init_files = Dir.glob(File.join(MetricFu.metrics_dir, '**/init.rb')).reject do |file|
47
46
  if file =~ /rcov/o
@@ -41,7 +41,7 @@ module MetricFu
41
41
  p.version = self.version
42
42
  p.option :run, "Run all metrics with defaults", :default => false
43
43
  metrics.each do |metric|
44
- p.option metric.to_sym, "Enables or disables #{metric.to_s.titleize}", :default => true #, :value_in_set => [true, false]
44
+ p.option metric.to_sym, "Enables or disables #{metric.to_s}", :default => true #, :value_in_set => [true, false]
45
45
  end
46
46
  p.option :open, "Open report in browser", :default => true
47
47
  end.process!(argv)
@@ -4,7 +4,7 @@ module MetricFu
4
4
 
5
5
  def initialize(contents,file_path='')
6
6
  if contents.to_s.size.zero?
7
- puts "NON PARSEABLE INPUT: File is empty at path #{file_path.inspect}\n\t#{caller.join("\n\t")}"
7
+ mf_log "NON PARSEABLE INPUT: File is empty at path #{file_path.inspect}\n\t#{caller.join("\n\t")}"
8
8
  else
9
9
  rp = RubyParser.new
10
10
  @locations = {}
@@ -14,19 +14,16 @@ module MetricFu
14
14
  process_class(file_sexp)
15
15
  when :module
16
16
  process_module(file_sexp)
17
- when :block
18
- file_sexp.each_of_type(:class) { |sexp| process_class(sexp) }
19
- when :iter
20
- mf_debug "SEXP: Not parsing line number for #{file_sexp.inspect}"
21
- when :cdecl
22
- mf_debug "SEXP: Not parsing line number for #{file_sexp.inspect}"
23
17
  else
24
- puts "Unexpected sexp_type #{file_sexp[0].inspect}"
18
+ mf_debug "SEXP: Parsing line numbers for classes in sexp type #{file_sexp[0].inspect}"
19
+ mf_debug " in #{file_path}"
20
+ file_sexp.each_of_type(:module) { |sexp| process_class(sexp) }
21
+ file_sexp.each_of_type(:class) { |sexp| process_class(sexp) }
25
22
  end
26
23
  end
27
24
  rescue Exception => e
28
25
  #catch errors for files ruby_parser fails on
29
- puts "RUBY PARSE FAILURE: #{e.class}\t#{e.message}\tSEXP:#{file_sexp.inspect}\n\tCONTENT:#{contents.inspect}\n\t#{e.backtrace}"
26
+ mf_log "RUBY PARSE FAILURE: #{e.class}\t#{e.message}\tFILE:#{file_path}\tSEXP:#{file_sexp.inspect}\n\tCONTENT:#{contents.inspect}\n\t#{e.backtrace}"
30
27
  @locations
31
28
  end
32
29
 
@@ -6,6 +6,7 @@ require 'rake'
6
6
 
7
7
  require 'yaml'
8
8
  require 'redcard'
9
+ require 'multi_json'
9
10
 
10
11
  MetricFu.configure
11
12
  MetricFu.logging_require { 'mf_debugger' }
@@ -1,24 +1,34 @@
1
1
  module MfDebugger
2
+ extend self
3
+
2
4
  class Logger
3
5
  class << self
4
6
  attr_accessor :debug_on
5
7
  @debug_on = false
6
8
  end
7
- end
8
-
9
- def self.mf_debug(msg,&block)
10
- if MfDebugger::Logger.debug_on
9
+ def self.log(msg, &block)
11
10
  if block_given?
12
11
  block.call
13
12
  end
14
- STDOUT.puts msg
13
+ STDOUT.puts '*'*5 + msg.to_s
14
+ end
15
+ def self.debug(msg, &block)
16
+ if MfDebugger::Logger.debug_on
17
+ if block_given?
18
+ log(msg,&block)
19
+ else
20
+ log(msg)
21
+ end
22
+ end
15
23
  end
16
24
  end
25
+
17
26
  def mf_debug(msg,&block)
18
- if block_given?
19
- MfDebugger.mf_debug(msg,&block)
20
- else
21
- MfDebugger.mf_debug(msg)
22
- end
27
+ MfDebugger::Logger.debug(msg, &block)
23
28
  end
29
+
30
+ def mf_log(msg,&block)
31
+ MfDebugger::Logger.log(msg, &block)
32
+ end
33
+
24
34
  end
@@ -6,7 +6,7 @@ module MetricFu
6
6
  #{BLUFF_DEFAULT_OPTIONS}
7
7
  g.title = 'Cane: code quality threshold violations';
8
8
  g.data('cane', [#{@cane_violations.join(',')}]);
9
- g.labels = #{@labels.to_json};
9
+ g.labels = #{MultiJson.dump(@labels)};
10
10
  g.draw();
11
11
  EOS
12
12
  File.open(File.join(MetricFu.output_directory, 'cane.js'), 'w') {|f| f << content }
@@ -6,7 +6,7 @@ module MetricFu
6
6
  #{BLUFF_DEFAULT_OPTIONS}
7
7
  g.title = 'Flay: duplication';
8
8
  g.data('flay', [#{@flay_score.join(',')}]);
9
- g.labels = #{@labels.to_json};
9
+ g.labels = #{MultiJson.dump(@labels)};
10
10
  g.draw();
11
11
  EOS
12
12
  File.open(File.join(MetricFu.output_directory, 'flay.js'), 'w') {|f| f << content }
@@ -27,7 +27,6 @@ module MetricFu
27
27
  end
28
28
  options = ::Flog.parse_options [
29
29
  "--all",
30
- "--details",
31
30
  MetricFu.flog[:continue] ? "--continue" : nil,
32
31
  ].compact
33
32
 
@@ -37,9 +36,9 @@ module MetricFu
37
36
  rescue LoadError => e
38
37
  message = "#{e.class}\t#{e.message}\n\t#{e.backtrace.join('\n\t')}"
39
38
  if MetricFu.configuration.mri?
40
- puts "Flog Error: #{message}"
39
+ mf_log "Flog Error: #{message}"
41
40
  else
42
- puts "Flog tasks only available in MRI: #{message}"
41
+ mf_log "Flog tasks only available in MRI: #{message}"
43
42
  end
44
43
  end
45
44
 
@@ -7,7 +7,7 @@ module MetricFu
7
7
  g.title = 'Flog: code complexity';
8
8
  g.data('average', [#{@flog_average.join(',')}]);
9
9
  g.data('top 5% average', [#{@top_five_percent_average.join(',')}])
10
- g.labels = #{@labels.to_json};
10
+ g.labels = #{MultiJson.dump(@labels)};
11
11
  g.draw();
12
12
  EOS
13
13
  File.open(File.join(MetricFu.output_directory, 'flog.js'), 'w') {|f| f << content }
@@ -20,9 +20,9 @@ module MetricFu
20
20
 
21
21
  def generate
22
22
  return if self.clazz.empty?
23
- puts "Generating graphs"
23
+ mf_log "Generating graphs"
24
24
  Dir[File.join(MetricFu.data_directory, '*.yml')].sort.each do |metric_file|
25
- puts "Generating graphs for #{metric_file}"
25
+ mf_log "Generating graphs for #{metric_file}"
26
26
  date_parts = year_month_day_from_filename(metric_file)
27
27
  metrics = YAML::load(File.open(metric_file))
28
28
 
@@ -6,7 +6,7 @@ module MetricFu
6
6
  #{BLUFF_DEFAULT_OPTIONS}
7
7
  g.title = 'Rails Best Practices: design problems';
8
8
  g.data('rails_best_practices', [#{@rails_best_practices_count.join(',')}]);
9
- g.labels = #{@labels.to_json};
9
+ g.labels = #{MultiJson.dump(@labels)};
10
10
  g.draw();
11
11
  EOS
12
12
  File.open(File.join(MetricFu.output_directory, 'rails_best_practices.js'), 'w') {|f| f << content }
@@ -81,7 +81,7 @@ module MetricFu
81
81
  line_numbers = MetricFu::LineNumbers.new(file_contents)
82
82
  rescue StandardError => e
83
83
  raise e unless e.message =~ /you shouldn't be able to get here/
84
- STDOUT.puts "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Rcov information for this file."
84
+ mf_log "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Rcov information for this file."
85
85
  next
86
86
  end
87
87
 
@@ -115,7 +115,7 @@ module MetricFu
115
115
  content.map! do |raw_line|
116
116
  line = Line.new(raw_line[3..-1], !raw_line.match(/^!!/)).to_h
117
117
  end
118
- content.reject! {|line| line[:content].blank? }
118
+ content.reject! {|line| line[:content].to_s == '' }
119
119
  files[fname] = {:lines => content}
120
120
  end
121
121
  files
@@ -6,7 +6,7 @@ module MetricFu
6
6
  #{BLUFF_DEFAULT_OPTIONS}
7
7
  g.title = 'Rcov: code coverage';
8
8
  g.data('rcov', [#{@rcov_percent.join(',')}]);
9
- g.labels = #{@labels.to_json};
9
+ g.labels = #{MultiJson.dump(@labels)};
10
10
  g.draw();
11
11
  EOS
12
12
  File.open(File.join(MetricFu.output_directory, 'rcov.js'), 'w') {|f| f << content }
@@ -66,7 +66,7 @@ module MetricFu
66
66
  line_numbers = MetricFu::LineNumbers.new(File.open(file_path, 'r').read,file_path)
67
67
  rescue StandardError => e
68
68
  raise e unless e.message =~ /you shouldn't be able to get here/
69
- puts "ruby_parser blew up while trying to parse #{file_path}. You won't have method level reek information for this file."
69
+ mf_log "ruby_parser blew up while trying to parse #{file_path}. You won't have method level reek information for this file."
70
70
  next
71
71
  end
72
72
 
@@ -11,7 +11,7 @@ module MetricFu
11
11
  #{BLUFF_DEFAULT_OPTIONS}
12
12
  g.title = 'Reek: code smells';
13
13
  #{data}
14
- g.labels = #{@labels.to_json};
14
+ g.labels = #{MultiJson.dump(@labels)};
15
15
  g.draw();
16
16
  EOS
17
17
  File.open(File.join(MetricFu.output_directory, 'reek.js'), 'w') {|f| f << content }
@@ -6,7 +6,7 @@ module MetricFu
6
6
  #{BLUFF_DEFAULT_OPTIONS}
7
7
  g.title = 'Roodi: design problems';
8
8
  g.data('roodi', [#{@roodi_count.join(',')}]);
9
- g.labels = #{@labels.to_json};
9
+ g.labels = #{MultiJson.dump(@labels)};
10
10
  g.draw();
11
11
  EOS
12
12
  File.open(File.join(MetricFu.output_directory, 'roodi.js'), 'w') {|f| f << content }
@@ -13,11 +13,35 @@ module MetricFu
13
13
  end
14
14
 
15
15
  saikuro_bin= $:.map{|d| d+'/../bin/saikuro'}.select{|f| File.exists? f}.first || 'saikuro'
16
- sh %{#{saikuro_bin} #{options_string}} do |ok, response|
17
- unless ok
18
- puts "Saikuro failed with exit status: #{response.exitstatus}"
16
+ mf_debug(capture_output do
17
+ sh %{#{saikuro_bin} #{options_string}} do |ok, response|
18
+ unless ok
19
+ mf_log "Saikuro failed with exit status: #{response.exitstatus}"
20
+ end
21
+ end
22
+ end)
23
+ end
24
+
25
+ def capture_output(&block)
26
+ old_stdout = STDOUT.clone
27
+ pipe_r, pipe_w = IO.pipe
28
+ pipe_r.sync = true
29
+ output = ""
30
+ reader = Thread.new do
31
+ begin
32
+ loop do
33
+ output << pipe_r.readpartial(1024)
34
+ end
35
+ rescue EOFError
19
36
  end
20
37
  end
38
+ STDOUT.reopen(pipe_w)
39
+ yield
40
+ ensure
41
+ STDOUT.reopen(old_stdout)
42
+ pipe_w.close
43
+ reader.join
44
+ return output
21
45
  end
22
46
 
23
47
  def format_directories
@@ -56,7 +80,7 @@ module MetricFu
56
80
  line_numbers = MetricFu::LineNumbers.new(File.open(file_data[:filename], 'r').read)
57
81
  rescue StandardError => e
58
82
  raise e unless e.message =~ /you shouldn't be able to get here/
59
- puts "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Saikuro information for this file."
83
+ mf_log "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Saikuro information for this file."
60
84
  next
61
85
  end
62
86
 
@@ -7,7 +7,7 @@ module MetricFu
7
7
  g.title = 'Stats: LOC & LOT';
8
8
  g.data('LOC', [#{@loc_counts.join(',')}]);
9
9
  g.data('LOT', [#{@lot_counts.join(',')}])
10
- g.labels = #{@labels.to_json};
10
+ g.labels = #{MultiJson.dump(@labels)};
11
11
  g.draw();
12
12
  EOS
13
13
  File.open(File.join(MetricFu.output_directory, 'stats.js'), 'w') {|f| f << content }
@@ -25,7 +25,7 @@ module MetricFu
25
25
  def self.require_graphing_gem
26
26
  require 'gchart' if MetricFu.graph_engine == :gchart
27
27
  rescue LoadError
28
- puts "#"*99 + "\n" +
28
+ mf_log "#"*99 + "\n" +
29
29
  "If you want to use google charts for graphing, you'll need to install the googlecharts rubygem." +
30
30
  "\n" + "#"*99
31
31
  end
@@ -21,12 +21,13 @@ module MetricFu
21
21
  end
22
22
  def run_reports
23
23
  report_metrics.each {|metric|
24
- mf_debug "** STARTING METRIC #{metric}"
24
+ mf_log "** STARTING METRIC #{metric}"
25
25
  MetricFu.report.add(metric)
26
- mf_debug "** ENDING METRIC #{metric}"
26
+ mf_log "** ENDING METRIC #{metric}"
27
27
  }
28
28
  end
29
29
  def save_reports
30
+ mf_log "** SAVING REPORTS"
30
31
  mf_debug "** SAVING REPORT YAML OUTPUT TO #{MetricFu.base_directory}"
31
32
  MetricFu.report.save_output(MetricFu.report.as_yaml,
32
33
  MetricFu.base_directory,
@@ -39,6 +40,7 @@ module MetricFu
39
40
  MetricFu.report.save_templatized_report
40
41
  end
41
42
  def save_graphs
43
+ mf_log "** GENERATING GRAPHS"
42
44
  mf_debug "** PREPARING TO GRAPH"
43
45
  MetricFu.graphs.each {|graph|
44
46
  mf_debug "** Graphing #{graph} with #{MetricFu.graph_engine}"
@@ -52,6 +54,7 @@ module MetricFu
52
54
  mf_debug "** OPENING IN BROWSER FROM #{MetricFu.output_directory}"
53
55
  MetricFu.report.show_in_browser(MetricFu.output_directory)
54
56
  end
57
+ mf_log "** COMPLETE"
55
58
  end
56
59
  private
57
60
  def load_user_configuration
@@ -1,3 +1,3 @@
1
1
  module MetricFu
2
- VERSION = "4.2.0"
2
+ VERSION = "4.2.1"
3
3
  end
@@ -55,6 +55,8 @@ Gem::Specification.new do |s|
55
55
  "coderay" => [],
56
56
  # default graphing libraries
57
57
  "bluff" => [],
58
+ # to_json support
59
+ 'multi_json' => [],
58
60
  }.each do |gem, version|
59
61
  if version == []
60
62
  s.add_runtime_dependency(gem)
@@ -10,7 +10,7 @@ describe Flog do
10
10
  describe "emit method" do
11
11
  it "should look for files and flog them" do
12
12
  Dir.should_receive(:glob).with("lib/**/*.rb").and_return(["found/file.rb"])
13
- ::Flog.should_receive(:parse_options).with(["--all", "--details"]).and_return("options")
13
+ ::Flog.should_receive(:parse_options).with(["--all"]).and_return("options")
14
14
  ::Flog.should_receive(:new).with("options").and_return(flogger = mock('flogger'))
15
15
  flogger.should_receive(:flog).with(["found/file.rb"])
16
16
  @flog.emit
@@ -27,11 +27,11 @@ describe MetricFu::Graph do
27
27
  @graph.clazz.should_receive(:push).with(an_instance_of(RcovGchartGrapher))
28
28
  @graph.add("rcov", 'gchart')
29
29
  end
30
- end
30
+ end
31
31
 
32
32
  describe "setting the date on the graph" do
33
33
  before(:each) do
34
- @graph.stub!(:puts)
34
+ @graph.stub!(:mf_log)
35
35
  end
36
36
 
37
37
  it "should set the date once for one data point" do
@@ -41,7 +41,7 @@ describe MetricFu::Graph do
41
41
  mock_grapher = stub
42
42
  mock_grapher.should_receive(:get_metrics).with("Metrics", "11/5")
43
43
  mock_grapher.should_receive(:graph!)
44
-
44
+
45
45
  @graph.clazz = [mock_grapher]
46
46
  @graph.generate
47
47
  end
@@ -57,5 +57,5 @@ describe MetricFu::Graph do
57
57
  @graph.clazz = [mock_grapher]
58
58
  @graph.generate
59
59
  end
60
- end
60
+ end
61
61
  end
@@ -1,3 +1,4 @@
1
+ require 'multi_json'
1
2
  require "spec_helper"
2
3
 
3
4
  describe Hotspots do
@@ -69,8 +70,8 @@ END
69
70
  analyzer = HotspotAnalyzer.new(@yaml)
70
71
  hotspots.instance_variable_set(:@analyzer, analyzer)
71
72
  result = hotspots.analyze
72
- expected = JSON.parse("{\"methods\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":\"Client#client_requested_sync\",\"file_path\":\"lib/client/client.rb\",\"hash\":7919384682,\"simple_method_name\":\"#client_requested_sync\"},\"details\":{\"reek\":\"found 1 code smells\",\"flog\":\"complexity is 37.9\"}}],\"classes\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":7995629750},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\"}}],\"files\":[{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":-5738801681},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\",\"churn\":\"detected high level of churn (changed 54 times)\"}},{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/foo.rb\",\"hash\":-7081271905},\"details\":{\"churn\":\"detected high level of churn (changed 52 times)\"}}]}")
73
- compare_hashes(JSON.parse(hotspots.to_h[:hotspots].to_json), expected)
73
+ expected = MultiJson.load("{\"methods\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":\"Client#client_requested_sync\",\"file_path\":\"lib/client/client.rb\",\"hash\":7919384682,\"simple_method_name\":\"#client_requested_sync\"},\"details\":{\"reek\":\"found 1 code smells\",\"flog\":\"complexity is 37.9\"}}],\"classes\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":7995629750},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\"}}],\"files\":[{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":-5738801681},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\",\"churn\":\"detected high level of churn (changed 54 times)\"}},{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/foo.rb\",\"hash\":-7081271905},\"details\":{\"churn\":\"detected high level of churn (changed 52 times)\"}}]}")
74
+ compare_hashes(MultiJson.load(hotspots.to_h[:hotspots].to_json), expected)
74
75
  end
75
76
 
76
77
  it "should put the changes into a hash" do
@@ -78,8 +79,8 @@ END
78
79
  analyzer = HotspotAnalyzer.new(@yaml)
79
80
  hotspots.instance_variable_set(:@analyzer, analyzer)
80
81
  hotspots.analyze
81
- expected = JSON.parse("{\"methods\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":\"Client#client_requested_sync\",\"file_path\":\"lib/client/client.rb\",\"hash\":7919384682,\"simple_method_name\":\"#client_requested_sync\"},\"details\":{\"reek\":\"found 1 code smells\",\"flog\":\"complexity is 37.9\"}}],\"classes\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":7995629750},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\"}}],\"files\":[{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":-5738801681},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\",\"churn\":\"detected high level of churn (changed 54 times)\"}},{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/foo.rb\",\"hash\":-7081271905},\"details\":{\"churn\":\"detected high level of churn (changed 52 times)\"}}]}")
82
- compare_hashes(JSON.parse(hotspots.to_h[:hotspots].to_json), expected)
82
+ expected = MultiJson.load("{\"methods\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":\"Client#client_requested_sync\",\"file_path\":\"lib/client/client.rb\",\"hash\":7919384682,\"simple_method_name\":\"#client_requested_sync\"},\"details\":{\"reek\":\"found 1 code smells\",\"flog\":\"complexity is 37.9\"}}],\"classes\":[{\"location\":{\"class_name\":\"Client\",\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":7995629750},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\"}}],\"files\":[{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/client.rb\",\"hash\":-5738801681},\"details\":{\"reek\":\"found 2 code smells\",\"flog\":\"complexity is 37.9\",\"churn\":\"detected high level of churn (changed 54 times)\"}},{\"location\":{\"class_name\":null,\"method_name\":null,\"file_path\":\"lib/client/foo.rb\",\"hash\":-7081271905},\"details\":{\"churn\":\"detected high level of churn (changed 52 times)\"}}]}")
83
+ compare_hashes(MultiJson.load(hotspots.to_h[:hotspots].to_json), expected)
83
84
  end
84
85
  # really testing the output of analyzed_problems#worst_items
85
86
  it "should return the worst item granularities: files, classes, methods" do
@@ -11,7 +11,7 @@ describe MetricFu::Rcov do
11
11
 
12
12
  describe "emit" do
13
13
  before :each do
14
- @rcov.stub!(:puts)
14
+ @rcov.stub!(:mf_log)
15
15
  MetricFu.rcov[:external] = nil
16
16
  end
17
17
 
@@ -65,7 +65,7 @@ describe MetricFu::Rcov do
65
65
  end
66
66
  describe "with external configuration option set" do
67
67
  before :each do
68
- @rcov.stub!(:puts)
68
+ @rcov.stub!(:mf_log)
69
69
  MetricFu.rcov[:external] = "coverage/rcov.txt"
70
70
  end
71
71
 
@@ -5,7 +5,7 @@ describe MetricFu::Grapher do
5
5
  it "should give a warning if trying to use gchart but gem is not installed" do
6
6
  MetricFu::Configuration.run {|config| config.graph_engine = :gchart}
7
7
  MetricFu::Grapher.should_receive(:require).with('gchart').and_raise(LoadError)
8
- MetricFu::Grapher.should_receive(:puts).with(/If you want to use google charts/)
8
+ MetricFu::Grapher.should_receive(:mf_log).with(/If you want to use google charts/)
9
9
  MetricFu::Grapher.require_graphing_gem
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metric_fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -19,7 +19,7 @@ authors:
19
19
  autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
- date: 2013-05-20 00:00:00.000000000 Z
22
+ date: 2013-05-23 00:00:00.000000000 Z
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: flay
@@ -321,6 +321,22 @@ dependencies:
321
321
  - - ! '>='
322
322
  - !ruby/object:Gem::Version
323
323
  version: '0'
324
+ - !ruby/object:Gem::Dependency
325
+ name: multi_json
326
+ requirement: !ruby/object:Gem::Requirement
327
+ none: false
328
+ requirements:
329
+ - - ! '>='
330
+ - !ruby/object:Gem::Version
331
+ version: '0'
332
+ type: :runtime
333
+ prerelease: false
334
+ version_requirements: !ruby/object:Gem::Requirement
335
+ none: false
336
+ requirements:
337
+ - - ! '>='
338
+ - !ruby/object:Gem::Version
339
+ version: '0'
324
340
  description: Code metrics from Flog, Flay, Saikuro, Churn, Reek, Roodi, Rails' stats
325
341
  task and Rails Best Practices, and optionally RCov
326
342
  email: github@benjaminfleischer.com
@@ -362,6 +378,7 @@ files:
362
378
  - bin/mf-stats
363
379
  - checksum/.gitkeep
364
380
  - checksum/metric_fu-4.2.0.gem.sha512
381
+ - checksum/metric_fu-4.2.1.gem.sha512
365
382
  - config/roodi_config.yml
366
383
  - gem_tasks/build.rake
367
384
  - lib/metric_fu.rb
@@ -369,14 +386,6 @@ files:
369
386
  - lib/metric_fu/cli/helper.rb
370
387
  - lib/metric_fu/cli/parser.rb
371
388
  - lib/metric_fu/configuration.rb
372
- - lib/metric_fu/core_ext.rb
373
- - lib/metric_fu/core_ext/inflector/inflections.rb
374
- - lib/metric_fu/core_ext/inflector/methods.rb
375
- - lib/metric_fu/core_ext/object.rb
376
- - lib/metric_fu/core_ext/object/blank.rb
377
- - lib/metric_fu/core_ext/object/to_json.rb
378
- - lib/metric_fu/core_ext/string.rb
379
- - lib/metric_fu/core_ext/string/inflections.rb
380
389
  - lib/metric_fu/data_structures/careful_array.rb
381
390
  - lib/metric_fu/data_structures/line_numbers.rb
382
391
  - lib/metric_fu/data_structures/location.rb
@@ -1,2 +0,0 @@
1
- MetricFu.lib_require { 'core_ext/object' }
2
- MetricFu.lib_require { 'core_ext/string' }
@@ -1,214 +0,0 @@
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
@@ -1,153 +0,0 @@
1
- # https://raw.github.com/rails/rails/20768176292cbcb883ab152b4aa9ed8c664771cd/activesupport/lib/active_support/inflector/methods.rb
2
- # not https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/inflector/methods.rb
3
- module ActiveSupport
4
- # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
5
- # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
6
- # in inflections.rb.
7
- #
8
- # The Rails core team has stated patches for the inflections library will not be accepted
9
- # in order to avoid breaking legacy applications which may be relying on errant inflections.
10
- # If you discover an incorrect inflection and require it for your application, you'll need
11
- # to correct it yourself (explained below).
12
- module Inflector
13
- extend self
14
-
15
- # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
16
- # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
17
- #
18
- # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
19
- #
20
- # Examples:
21
- # "active_record".camelize # => "ActiveRecord"
22
- # "active_record".camelize(:lower) # => "activeRecord"
23
- # "active_record/errors".camelize # => "ActiveRecord::Errors"
24
- # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
25
- #
26
- # As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
27
- # though there are cases where that does not hold:
28
- #
29
- # "SSLError".underscore.camelize # => "SslError"
30
- def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
31
- if first_letter_in_uppercase
32
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
33
- else
34
- lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
35
- end
36
- end
37
-
38
- # Makes an underscored, lowercase form from the expression in the string.
39
- #
40
- # Changes '::' to '/' to convert namespaces to paths.
41
- #
42
- # Examples:
43
- # "ActiveRecord".underscore # => "active_record"
44
- # "ActiveRecord::Errors".underscore # => active_record/errors
45
- #
46
- # As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
47
- # though there are cases where that does not hold:
48
- #
49
- # "SSLError".underscore.camelize # => "SslError"
50
- def underscore(camel_cased_word)
51
- word = camel_cased_word.to_s.dup
52
- word.gsub!(/::/, '/')
53
- word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
54
- word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
55
- word.tr!("-", "_")
56
- word.downcase!
57
- word
58
- end
59
-
60
- # Replaces underscores with dashes in the string.
61
- #
62
- # Example:
63
- # "puni_puni" # => "puni-puni"
64
- def dasherize(underscored_word)
65
- underscored_word.gsub(/_/, '-')
66
- end
67
-
68
- # Removes the module part from the expression in the string.
69
- #
70
- # Examples:
71
- # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
72
- # "Inflections".demodulize # => "Inflections"
73
- def demodulize(class_name_in_module)
74
- class_name_in_module.to_s.gsub(/^.*::/, '')
75
- end
76
-
77
- # Creates a foreign key name from a class name.
78
- # +separate_class_name_and_id_with_underscore+ sets whether
79
- # the method should put '_' between the name and 'id'.
80
- #
81
- # Examples:
82
- # "Message".foreign_key # => "message_id"
83
- # "Message".foreign_key(false) # => "messageid"
84
- # "Admin::Post".foreign_key # => "post_id"
85
- def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
86
- underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
87
- end
88
-
89
- # Ruby 1.9 introduces an inherit argument for Module#const_get and
90
- # #const_defined? and changes their default behavior.
91
- if Module.method(:const_get).arity == 1
92
- # Tries to find a constant with the name specified in the argument string:
93
- #
94
- # "Module".constantize # => Module
95
- # "Test::Unit".constantize # => Test::Unit
96
- #
97
- # The name is assumed to be the one of a top-level constant, no matter whether
98
- # it starts with "::" or not. No lexical context is taken into account:
99
- #
100
- # C = 'outside'
101
- # module M
102
- # C = 'inside'
103
- # C # => 'inside'
104
- # "C".constantize # => 'outside', same as ::C
105
- # end
106
- #
107
- # NameError is raised when the name is not in CamelCase or the constant is
108
- # unknown.
109
- def constantize(camel_cased_word)
110
- names = camel_cased_word.split('::')
111
- names.shift if names.empty? || names.first.empty?
112
-
113
- constant = Object
114
- names.each do |name|
115
- constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
116
- end
117
- constant
118
- end
119
- else
120
- def constantize(camel_cased_word) #:nodoc:
121
- names = camel_cased_word.split('::')
122
- names.shift if names.empty? || names.first.empty?
123
-
124
- constant = Object
125
- names.each do |name|
126
- constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
127
- end
128
- constant
129
- end
130
- end
131
-
132
- # Turns a number into an ordinal string used to denote the position in an
133
- # ordered sequence such as 1st, 2nd, 3rd, 4th.
134
- #
135
- # Examples:
136
- # ordinalize(1) # => "1st"
137
- # ordinalize(2) # => "2nd"
138
- # ordinalize(1002) # => "1002nd"
139
- # ordinalize(1003) # => "1003rd"
140
- def ordinalize(number)
141
- if (11..13).include?(number.to_i % 100)
142
- "#{number}th"
143
- else
144
- case number.to_i % 10
145
- when 1; "#{number}st"
146
- when 2; "#{number}nd"
147
- when 3; "#{number}rd"
148
- else "#{number}th"
149
- end
150
- end
151
- end
152
- end
153
- end
@@ -1,3 +0,0 @@
1
- # https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/core_ext/object.rb
2
- MetricFu.lib_require { 'core_ext/object/blank' }
3
- MetricFu.lib_require { 'core_ext/object/to_json' }
@@ -1,106 +0,0 @@
1
- # https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/core_ext/object/blank.rb
2
- # encoding: utf-8
3
-
4
- class Object
5
- # An object is blank if it's false, empty, or a whitespace string.
6
- # For example, '', ' ', +nil+, [], and {} are all blank.
7
- #
8
- # This simplifies:
9
- #
10
- # if address.nil? || address.empty?
11
- #
12
- # ...to:
13
- #
14
- # if address.blank?
15
- def blank?
16
- respond_to?(:empty?) ? empty? : !self
17
- end
18
-
19
- # An object is present if it's not <tt>blank?</tt>.
20
- def present?
21
- !blank?
22
- end
23
-
24
- # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
25
- # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
26
- #
27
- # This is handy for any representation of objects where blank is the same
28
- # as not present at all. For example, this simplifies a common check for
29
- # HTTP POST/query parameters:
30
- #
31
- # state = params[:state] if params[:state].present?
32
- # country = params[:country] if params[:country].present?
33
- # region = state || country || 'US'
34
- #
35
- # ...becomes:
36
- #
37
- # region = params[:state].presence || params[:country].presence || 'US'
38
- def presence
39
- self if present?
40
- end
41
- end
42
-
43
- class NilClass
44
- # +nil+ is blank:
45
- #
46
- # nil.blank? # => true
47
- def blank?
48
- true
49
- end
50
- end
51
-
52
- class FalseClass
53
- # +false+ is blank:
54
- #
55
- # false.blank? # => true
56
- def blank?
57
- true
58
- end
59
- end
60
-
61
- class TrueClass
62
- # +true+ is not blank:
63
- #
64
- # true.blank? # => false
65
- def blank?
66
- false
67
- end
68
- end
69
-
70
- class Array
71
- # An array is blank if it's empty:
72
- #
73
- # [].blank? # => true
74
- # [1,2,3].blank? # => false
75
- alias_method :blank?, :empty?
76
- end
77
-
78
- class Hash
79
- # A hash is blank if it's empty:
80
- #
81
- # {}.blank? # => true
82
- # { key: 'value' }.blank? # => false
83
- alias_method :blank?, :empty?
84
- end
85
-
86
- class String
87
- # A string is blank if it's empty or contains whitespaces only:
88
- #
89
- # ''.blank? # => true
90
- # ' '.blank? # => true
91
- # ' '.blank? # => true
92
- # ' something here '.blank? # => false
93
- def blank?
94
- self !~ /[^[:space:]]/
95
- end
96
- end
97
-
98
- class Numeric #:nodoc:
99
- # No number is blank:
100
- #
101
- # 1.blank? # => false
102
- # 0.blank? # => false
103
- def blank?
104
- false
105
- end
106
- end
@@ -1,12 +0,0 @@
1
- # https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/core_ext/object/to_json.rb
2
- # Hack to load json gem first so we can overwrite its to_json.
3
- begin
4
- require 'json'
5
- rescue LoadError
6
- end
7
-
8
- # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
9
- # their default behavior. That said, we need to define the basic to_json method in all of them,
10
- # otherwise they will always use to_json gem implementation, which is backwards incompatible in
11
- # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
12
- # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
@@ -1,2 +0,0 @@
1
- # https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/core_ext/string.rb
2
- MetricFu.lib_require { 'core_ext/string/inflections' }
@@ -1,195 +0,0 @@
1
- # https://github.com/rails/rails/blob/e8727d37fc49d5bf9976c3cb5c46badb92cf4ced/activesupport/lib/active_support/core_ext/string/inflections.rb
2
- MetricFu.lib_require { 'core_ext/inflector/inflections' }
3
-
4
- # String inflections define new methods on the String class to transform names for different purposes.
5
- # For instance, you can figure out the name of a table from the name of a class.
6
- #
7
- # 'ScaleScore'.tableize # => "scale_scores"
8
- #
9
- class String
10
- # Returns the plural form of the word in the string.
11
- #
12
- # If the optional parameter +count+ is specified,
13
- # the singular form will be returned if <tt>count == 1</tt>.
14
- # For any other value of +count+ the plural will be returned.
15
- #
16
- # If the optional parameter +locale+ is specified,
17
- # the word will be pluralized as a word of that language.
18
- # By default, this parameter is set to <tt>:en</tt>.
19
- # You must define your own inflection rules for languages other than English.
20
- #
21
- # 'post'.pluralize # => "posts"
22
- # 'octopus'.pluralize # => "octopi"
23
- # 'sheep'.pluralize # => "sheep"
24
- # 'words'.pluralize # => "words"
25
- # 'the blue mailman'.pluralize # => "the blue mailmen"
26
- # 'CamelOctopus'.pluralize # => "CamelOctopi"
27
- # 'apple'.pluralize(1) # => "apple"
28
- # 'apple'.pluralize(2) # => "apples"
29
- # 'ley'.pluralize(:es) # => "leyes"
30
- # 'ley'.pluralize(1, :es) # => "ley"
31
- def pluralize(count = nil, locale = :en)
32
- locale = count if count.is_a?(Symbol)
33
- if count == 1
34
- self
35
- else
36
- ActiveSupport::Inflector.pluralize(self, locale)
37
- end
38
- end
39
-
40
- # The reverse of +pluralize+, returns the singular form of a word in a string.
41
- #
42
- # If the optional parameter +locale+ is specified,
43
- # the word will be singularized as a word of that language.
44
- # By default, this parameter is set to <tt>:en</tt>.
45
- # You must define your own inflection rules for languages other than English.
46
- #
47
- # 'posts'.singularize # => "post"
48
- # 'octopi'.singularize # => "octopus"
49
- # 'sheep'.singularize # => "sheep"
50
- # 'word'.singularize # => "word"
51
- # 'the blue mailmen'.singularize # => "the blue mailman"
52
- # 'CamelOctopi'.singularize # => "CamelOctopus"
53
- # 'leyes'.singularize(:es) # => "ley"
54
- def singularize(locale = :en)
55
- ActiveSupport::Inflector.singularize(self, locale)
56
- end
57
-
58
- # +constantize+ tries to find a declared constant with the name specified
59
- # in the string. It raises a NameError when the name is not in CamelCase
60
- # or is not initialized. See ActiveSupport::Inflector.constantize
61
- #
62
- # 'Module'.constantize # => Module
63
- # 'Class'.constantize # => Class
64
- # 'blargle'.constantize # => NameError: wrong constant name blargle
65
- def constantize
66
- ActiveSupport::Inflector.constantize(self)
67
- end
68
-
69
- # +safe_constantize+ tries to find a declared constant with the name specified
70
- # in the string. It returns nil when the name is not in CamelCase
71
- # or is not initialized. See ActiveSupport::Inflector.safe_constantize
72
- #
73
- # 'Module'.safe_constantize # => Module
74
- # 'Class'.safe_constantize # => Class
75
- # 'blargle'.safe_constantize # => nil
76
- def safe_constantize
77
- ActiveSupport::Inflector.safe_constantize(self)
78
- end
79
-
80
- # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
81
- # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
82
- #
83
- # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
84
- #
85
- # 'active_record'.camelize # => "ActiveRecord"
86
- # 'active_record'.camelize(:lower) # => "activeRecord"
87
- # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
88
- # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
89
- def camelize(first_letter = :upper)
90
- case first_letter
91
- when :upper
92
- ActiveSupport::Inflector.camelize(self, true)
93
- when :lower
94
- ActiveSupport::Inflector.camelize(self, false)
95
- end
96
- end
97
- alias_method :camelcase, :camelize
98
-
99
- # Capitalizes all the words and replaces some characters in the string to create
100
- # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
101
- # used in the Rails internals.
102
- #
103
- # +titleize+ is also aliased as +titlecase+.
104
- #
105
- # 'man from the boondocks'.titleize # => "Man From The Boondocks"
106
- # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
107
- def titleize
108
- ActiveSupport::Inflector.titleize(self)
109
- end
110
- alias_method :titlecase, :titleize
111
-
112
- # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
113
- #
114
- # +underscore+ will also change '::' to '/' to convert namespaces to paths.
115
- #
116
- # 'ActiveModel'.underscore # => "active_model"
117
- # 'ActiveModel::Errors'.underscore # => "active_model/errors"
118
- def underscore
119
- ActiveSupport::Inflector.underscore(self)
120
- end
121
-
122
- # Replaces underscores with dashes in the string.
123
- #
124
- # 'puni_puni'.dasherize # => "puni-puni"
125
- def dasherize
126
- ActiveSupport::Inflector.dasherize(self)
127
- end
128
-
129
- # Removes the module part from the constant expression in the string.
130
- #
131
- # 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
132
- # 'Inflections'.demodulize # => "Inflections"
133
- #
134
- # See also +deconstantize+.
135
- def demodulize
136
- ActiveSupport::Inflector.demodulize(self)
137
- end
138
-
139
- # Removes the rightmost segment from the constant expression in the string.
140
- #
141
- # 'Net::HTTP'.deconstantize # => "Net"
142
- # '::Net::HTTP'.deconstantize # => "::Net"
143
- # 'String'.deconstantize # => ""
144
- # '::String'.deconstantize # => ""
145
- # ''.deconstantize # => ""
146
- #
147
- # See also +demodulize+.
148
- def deconstantize
149
- ActiveSupport::Inflector.deconstantize(self)
150
- end
151
-
152
- # Creates the name of a table like Rails does for models to table names. This method
153
- # uses the +pluralize+ method on the last word in the string.
154
- #
155
- # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
156
- # 'egg_and_ham'.tableize # => "egg_and_hams"
157
- # 'fancyCategory'.tableize # => "fancy_categories"
158
- def tableize
159
- ActiveSupport::Inflector.tableize(self)
160
- end
161
-
162
- # Create a class name from a plural table name like Rails does for table names to models.
163
- # Note that this returns a string and not a class. (To convert to an actual class
164
- # follow +classify+ with +constantize+.)
165
- #
166
- # 'egg_and_hams'.classify # => "EggAndHam"
167
- # 'posts'.classify # => "Post"
168
- #
169
- # Singular names are not handled correctly.
170
- #
171
- # 'business'.classify # => "Busines"
172
- def classify
173
- ActiveSupport::Inflector.classify(self)
174
- end
175
-
176
- # Capitalizes the first word, turns underscores into spaces, and strips '_id'.
177
- # Like +titleize+, this is meant for creating pretty output.
178
- #
179
- # 'employee_salary'.humanize # => "Employee salary"
180
- # 'author_id'.humanize # => "Author"
181
- def humanize
182
- ActiveSupport::Inflector.humanize(self)
183
- end
184
-
185
- # Creates a foreign key name from a class name.
186
- # +separate_class_name_and_id_with_underscore+ sets whether
187
- # the method should put '_' between the name and 'id'.
188
- #
189
- # 'Message'.foreign_key # => "message_id"
190
- # 'Message'.foreign_key(false) # => "messageid"
191
- # 'Admin::Post'.foreign_key # => "post_id"
192
- def foreign_key(separate_class_name_and_id_with_underscore = true)
193
- ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
194
- end
195
- end