Class: RailsDoctor::Project

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_doctor/project.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root:, runner: nil) ⇒ Project

Returns a new instance of Project.



9
10
11
12
# File 'lib/rails_doctor/project.rb', line 9

def initialize(root:, runner: nil)
  @root = File.expand_path(root)
  @runner = runner || CommandRunner.new(project_root: @root)
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



7
8
9
# File 'lib/rails_doctor/project.rb', line 7

def root
  @root
end

#runnerObject (readonly)

Returns the value of attribute runner.



7
8
9
# File 'lib/rails_doctor/project.rb', line 7

def runner
  @runner
end

Instance Method Details

#changed_files(base_ref: nil) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rails_doctor/project.rb', line 58

def changed_files(base_ref: nil)
  if base_ref && !base_ref.to_s.strip.empty?
    result = runner.run("git diff --name-only #{base_ref.shellescape}...HEAD", timeout_seconds: 20)
    return result.stdout.lines.map(&:strip).uniq.reject(&:empty?) if result.exit_status == 0
  end

  names = []
  ["git diff --name-only", "git diff --cached --name-only"].each do |command|
    result = runner.run(command, timeout_seconds: 10)
    names.concat(result.stdout.lines.map(&:strip)) if result.exit_status == 0
  end
  names.uniq.reject(&:empty?)
end

#churn(window_days:) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/rails_doctor/project.rb', line 72

def churn(window_days:)
  since = (Time.now - (window_days.to_i * 86_400)).strftime("%Y-%m-%d")
  command = "git log --since=#{since} --name-only --pretty=format:"
  result = runner.run(command, timeout_seconds: 20)
  return {} unless result.exit_status == 0

  result.stdout.lines.map(&:strip).reject(&:empty?).each_with_object(Hash.new(0)) do |file, counts|
    counts[file] += 1
  end
end

#command_available?(name) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/rails_doctor/project.rb', line 42

def command_available?(name)
  runner.executable?(name) || File.executable?(join("bin/#{name}"))
end

#current_branchObject



46
47
48
49
50
51
# File 'lib/rails_doctor/project.rb', line 46

def current_branch
  result = runner.run("git rev-parse --abbrev-ref HEAD", timeout_seconds: 5)
  return nil unless result.exit_status == 0

  result.stdout.strip
end

#dirty_worktree?Boolean

Returns:

  • (Boolean)


53
54
55
56
# File 'lib/rails_doctor/project.rb', line 53

def dirty_worktree?
  result = runner.run("git status --porcelain", timeout_seconds: 5)
  result.exit_status == 0 && !result.stdout.strip.empty?
end

#files(pattern) ⇒ Object



83
84
85
# File 'lib/rails_doctor/project.rb', line 83

def files(pattern)
  Dir.glob(join(pattern)).select { |path| File.file?(path) }
end

#gem_declared?(name) ⇒ Boolean

Returns:

  • (Boolean)


18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rails_doctor/project.rb', line 18

def gem_declared?(name)
  [join("Gemfile"), join("Gemfile.lock")].any? do |path|
    next false unless File.exist?(path)

    content = File.read(path)
    content.include?(%("#{name}")) ||
      content.include?(%('#{name}')) ||
      content.match?(/^\s{4}#{Regexp.escape(name)}\s/) ||
      content.match?(/^\s{2}#{Regexp.escape(name)}\s/)
  end
end

#gem_version(name) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/rails_doctor/project.rb', line 30

def gem_version(name)
  lockfile = join("Gemfile.lock")
  return nil unless File.exist?(lockfile)

  escaped = Regexp.escape(name)
  File.read(lockfile)[/^\s{4}#{escaped} \(([^)]+)\)/, 1]
end

#join(*parts) ⇒ Object



91
92
93
# File 'lib/rails_doctor/project.rb', line 91

def join(*parts)
  File.join(root, *parts)
end

#rails_app?Boolean

Returns:

  • (Boolean)


14
15
16
# File 'lib/rails_doctor/project.rb', line 14

def rails_app?
  File.exist?(join("config/application.rb")) || File.exist?(join("bin/rails")) || gem_declared?("rails")
end

#rails_versionObject



38
39
40
# File 'lib/rails_doctor/project.rb', line 38

def rails_version
  gem_version("rails")
end

#relative(path) ⇒ Object



87
88
89
# File 'lib/rails_doctor/project.rb', line 87

def relative(path)
  path.to_s.delete_prefix("#{root}/")
end